Статьи

Создание веб-приложений с нуля с помощью Laravel: фильтры, проверки и файлы

В этой мини-серии Nettuts + мы создадим веб-приложение с нуля, в то же время погрузившись в великолепную новую среду PHP, которая быстро набирает обороты и называется Laravel .

На этом уроке мы узнаем о некоторых очень полезных функциях Laravel: фильтрах, а также библиотеках проверки и файлов.


Добро пожаловать в наши веб-приложения с нуля с серией Laravel! Во втором уроке нашего мини-сериала мы узнали много нового о реализации ORM в Laravel:

  • Немного истории о «Моделях»
  • Что такое Eloquent ORM
  • Как настроить конфигурацию базы данных Laravel
  • Как создать свою первую модель Laravel
  • Основные функции библиотек Auth и Input
  • Использование Eloquent ORM в представлении

Если вы еще этого не видели, я призываю вас ознакомиться с первой и второй частью мини-серии — это значительно облегчит отслеживание, поскольку мы создаем наше тестовое приложение Instapics для каждой части.

Итак, начнем!


В двух словах, фильтры — это функции, которые мы можем запускать на маршрутах before или after цикла запроса. Это особенно полезно для таких вещей, как аутентификация и регистрация. Чтобы зарегистрировать фильтр, нам нужно добавить что-то вроде следующего в файл application / rout.php :

1
2
3
4
Route::filter(‘myfilter’, function()
{
    //What you want the filter to do
});

После того, как мы зарегистрировали фильтр, нам нужно прикрепить его к маршруту, например так:

1
2
3
4
Route::any(‘/’, array(‘before’ => ‘filter’, function()
{
    //What you want the route to do
}));

В приведенном выше примере myfilter сработает при всех запросах к странице индекса (т. myfilter / ). Допустим, мы хотели реализовать фильтр аутентификации для маршрута dashboard :

01
02
03
04
05
06
07
08
09
10
11
Route::filter(‘auth’, function()
{
    if(Auth::guest()) {
        return Redirect::to(‘home’);
    }
});
 
Route::any(‘dashboard’, array(‘before’ => ‘auth, function()
{
    return View::make(‘dashboard’);
});

Приведенный выше код перенаправит все неаутентифицированные запросы на маршрут панели мониторинга к домашнему маршруту.

По умолчанию Laravel включает два фильтра, before и after , которые запускаются до и после каждого запроса к приложению. Обычно это место, где вы размещаете такие вещи, как ведение журнала запросов, добавление глобальных активов или запуск глобальных событий. Например:

1
2
3
4
Route::filter(‘after’, function($response)
{
    Log::write(‘request’, ‘Request finished on ‘ . date(‘d M, Y — h:i:sA’) . ‘.\n\nRequest Information:\n ‘. var_export(Input::get(), true));
});

Это записывает сообщение журнала типа request журнал приложения и перечисляет любые входные данные запроса.

Если вы обнаружите, что применяете один и тот же фильтр к нескольким маршрутам, вы можете использовать группы маршрутов, чтобы сгруппировать их все вместе и уменьшить количество повторений кода:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
Route::filter(‘admin_auth’, function()
{
    if(Auth::guest() || !Auth::user()->isAdmin()) {
        return Redirect::to(‘home’);
    }
});
 
Route::group(array(‘before’ => ‘admin_auth’), function()
{
    Route::get(‘admin’, function()
    {
        return View::make(‘admin’);
    });
 
    Route::get(‘useradmin’, function()
    {
        return View::make(‘useradmin’);
    });
});

Для приложений (таких как наши собственные Instapics ), которые используют контроллеры, мы можем применять фильтры, используя функцию $this->filter() в конструкторе контроллера:

1
2
3
4
public function __construct()
{
    $this->filter(‘before’, ‘auth’);
}

Эти фильтры, такие как маршруты, также можно настроить для применения только к определенным HTTP-глаголам и конкретным действиям контроллера:

1
2
3
4
5
6
7
8
public function __construct()
{
    //call ‘log_download’ filter for all download/file GET requests
    $this->filter(‘after’, ‘log_download’)->only(array(‘file’))->on(‘get’);
     
    //call the ‘auth_download’ filter for all download/* requests, except for the ‘queue’ action
    $this->filter(‘before’, ‘auth_download’)->except(array(‘queue’));
}

Встроенная в Laravel валидация позволяет легко применять валидацию к любому массиву значений, в частности, к вводу формы. Для этого вам просто нужно построить два массива:

  • $ input — это ассоциативный массив значений, которые вы хотите проверить.
  • $ rules — это ассоциативный массив (с ключами, совпадающими с массивом $ input), в котором перечислены правила проверки.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
//Getting our input from the Input library
$input = Input::all();
//Create our validation rules
$rules = array(
    ’email’ => ‘required|email|unique:users’,
    ‘password’ => ‘required’
);
 
//Getting a $validation instance for our error checking
$validation = Validator::make($input, $rules);
 
//Check if the validation succeeded
if( $validation->fails() ) {
    //do something with the error messages from the $validation instance
    $validation->errors;
}

Ниже приведен список правил проверки, которые можно использовать с библиотекой проверки Laravel. Как и в примере выше, вы можете смешивать и сопоставлять их, разделяя их с помощью трубы (» | «):

  • required — значение должно присутствовать во входном массиве

    1
    ’email’ => ‘required’
  • alpha — значение должно состоять только из букв алфавита

    1
    ‘full_name’ => ‘alpha’
  • alpha_num — значение должно состоять только из буквенно-цифровых символов

    1
    ‘username’ => ‘alpha_num’
  • alpha_dash — значение должно состоять только из буквенно-цифровых символов, тире и / или подчеркиваний

    1
    ‘user_name’ => ‘alpha_dash’
  • size — значение должно иметь только заданную длину или должно быть равно, если числовой

    1
    ‘api_key’ => ‘size:10’
    1
    ‘order_count’ => ‘size:10’
  • between — значение включительно между указанным диапазоном

    1
    ‘order_count’ => ‘between:1,100’
  • min — значение как минимум заданное

    1
    ‘order_count’ => ‘min:1’
  • max — значение равно или меньше заданного

    1
    ‘order_count’ => ‘max:100’
  • numeric — значение числовое

    1
    ‘order_count’ => ‘numeric’
  • integer — значение является целым числом

    1
    ‘order_count’ => ‘integer’
  • in — значение содержится в данном

    1
    ‘tshirt_size’ => ‘in:xsmall,small,medium,large,xlarge’
  • not_in — значение не в данном

    1
    ‘tshirt_size’ => ‘not_in:xsmall,xlarge’
  • confirmed — проверит, существует ли key _confirmation и равен ли он значению

    1
    ‘password’ => ‘confirmed’

    Это проверит, существует ли значение password_confirmation и равно ли оно password

  • accepted — это проверит, установлено ли значение «да» или 1. Полезно для флажков

    1
    ‘terms_of_service’ => ‘accepted’
  • same — значение совпадает со значением данного атрибута

    1
    ‘password’ => ‘same:confirm_password’
  • different — значение должно отличаться от значения данного атрибута

    1
    ‘password’ => ‘different:old_password’
  • match — значение должно соответствовать заданному регулярному выражению

    1
    ‘user_name’ => ‘match:/[a-zA-Z0-9]*/’
  • unique — проверяет уникальность значения в данной таблице.

    1
    ‘user_name’ => ‘unique:users’

    Данный столбец также принимается, если имя столбца не совпадает с именем атрибута.

    1
    2
    3
    //if the column in the users table is username,
           //we can provide this in the given like so:
           ‘user_name’ => ‘unique:users,username’

    Есть моменты, когда мы хотим проверить уникальность, но игнорируем определенную запись (обычно запись, связанную с текущим пользователем). Мы можем сделать это, добавив третье значение, которое должно быть идентификатором этой записи в таблице.

    1
    2
    //ID 10 is the record ID of the current user
           ‘user_name’ => ‘unique:users,user_name,10’
  • exists — значение должно существовать в таблице

    1
    ‘category’ => ‘exists:categories’

    Это также принимает второе значение, если мы хотим изменить имя столбца для проверки.

    1
    ‘category’ => ‘exists:categories,category_name’
  • before — значение должно быть датой до указанной даты

    1
    ‘publish_date’ => ‘before:2012-07-14’
  • after — значение должно быть датой после данной даты

    1
    ‘publish_date’ => ‘after:2012-07-14’
  • email — значение должно быть в правильном формате электронной почты

    1
    ‘subscriber_email’ => ’email’
  • url — значение в правильном формате URL

    1
    ‘github_profile’ => ‘url’
  • active_url — значение в правильном формате URL и активно

    1
    ‘github_profile’ => ‘active_url’
  • mimes — проверяет тип mime загруженного файла. Вы можете использовать любое значение mime-type из файла config / mimes.php

    1
    ‘avatar’ => ‘mimes:jpg,gif,png,bmp’
  • image — файл должен быть изображением

    1
    ‘avatar’ => ‘image’

    Вы также можете использовать max валидатор здесь, чтобы проверить размер файла в килобайтах

    1
    ‘avatar’ => ‘image|max:100’

Когда вы вызываете метод Validator->fails() или Validator->passes() , библиотека собирает все ошибки в классе, который доступен через Validator->errors . После этого вы сможете получить эти ошибки с помощью некоторых функций в классе errors . Laravel предоставляет некоторые интересные функции для автоматизации обработки ошибок, которые подходят для большинства сценариев POST / REDIRECT / GET:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Register_Controller extends Base_Controller
{
    public $restful = true;
     
    public function get_index()
    {
        return View::make(‘register.index’);
    }
     
    public function post_index()
    {
        $rules = array(
            ’email’ => ‘required|email|unique:users’,
            ‘password’ => ‘confirmed’
        );
         
        $validation = Validator::make(Input::get(), $rules);
         
        if( $validation->fails() ) {
            //Send the $validation object to the redirected page
            return Redirect::to(‘register’)->with_errors($validation);
        }
    }
}

Здесь мы используем метод with_errors для библиотеки Redirect . Это автоматически связывает переменную $errors в представлении, куда бы мы ни перенаправляли — в данном случае это страница register/index :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
<form>
    {{— $errors variable passed via with_errors —}}
    @if ($errors->has(’email’))
    @foreach ($errors->get(’email’, ‘<p class=»error-message»>:message</p>’) as $email_error)
    {{ $email_error }}
    @endforeach
    @endif
    <label for=»email»>Email:</label>
    <input type=»email» name=»email» placeholder=»Enter your email address here» />
 
    @if ($errors->has(‘password’))
    @foreach ($errors->get(‘password’, ‘<p class=»error-message»>:message</p>’) as $password_error)
    {{ $password_error }}
    @endif
    <label for=»password»>Password:</label>
    <input type=»password» name=»password» placeholder=»Enter your password here» />
     
    <label for=»password_confirmation»>Confirm Password:</label>
    <input type=»password» name=»password_confirmation» placeholder=»Re-type your password here» />
</form>

В файле представления мы используем метод $errors->has() чтобы проверить, существует ли ошибка для указанного поля. Если это так, мы используем метод $errors->get() для отображения сообщений об ошибках. Второй параметр в этом методе можно использовать для предоставления шаблона для отображения сообщения об ошибке.

Поскольку большинство людей хотели бы изменить сообщения об ошибках для Laravel, чтобы они соответствовали брендингу или языку их приложения, библиотека Validation также позволяет настраивать сообщения об ошибках, которые генерируются путем простого добавления массива $messages в вызов функции Validate::make :

01
02
03
04
05
06
07
08
09
10
11
12
$rules = array(
    ’email’ => ‘required|email|unique:users’,
    ‘password’ => ‘confirmed’
);
 
$messages = array(
    ’email_required’ => ‘Please provide an email address’,
    ’email_email’ => ‘Please provide a valid email address’,
    ’email_unique’ => ‘The email address you provided is already being used’,
    ‘password_confirmed’ => ‘Your password confirmation did not match your password.’
);
$validation = Validator::make(Input::get(), $rules, $messages);

Есть два способа создать массив $messages :

  • На основе правил — вы можете предоставить настраиваемое сообщение для всех полей, проверенных по определенному правилу. Например:

    1
    2
    3
    4
    5
    6
    7
    $messages = array(
               ‘required’ => ‘The :attribute field is required.’,
               ‘same’ => ‘The :attribute and :other must match.’,
               ‘size’ => ‘The :attribute must be exactly :size.’,
               ‘between’ => ‘The :attribute must be between :min — :max.’,
               ‘in’ => ‘The :attribute must be one of the following types: :values’,
           );

    Это изменит сообщения об ошибках по умолчанию для всех полей, имеющих required, same, size, between and in правилах. Здесь мы также видим, что Laravel использует заполнители для замены определенных значений в сообщении об ошибке. :attribute изменится на атрибут поля (без подчеркивания), для которого он. :other используется для того same правила, которое ссылается на другой атрибут, которому он должен соответствовать. :size относится к определенному размеру в параметрах правила. :min и :max — это минимальное и максимальное значения, а :values — список значений, которые мы указали, в которых должно быть указано значение поля.

  • На основе атрибутов — с другой стороны, вы также можете предоставить настраиваемое сообщение для определенного атрибута в определенном правиле. Взяв наш пример сверху:

    1
    2
    3
    4
    5
    6
    $messages = array(
               ’email_required’ => ‘Please provide an email address’,
               ’email_email’ => ‘Please provide a valid email address’,
               ’email_unique’ => ‘The email address you provided is already being used’,
               ‘password_confirmed’ => ‘Your password confirmation did not match your password.’
           );

    email_required — это сообщение об ошибке, которое используется, когда атрибут email не соответствует required правилу, email_email — это сообщение об ошибке, которое используется, когда email не соответствует правилу email и т. д.

Однако, если вы постоянно воссоздаете одни и те же пользовательские сообщения, было бы проще просто указать пользовательские сообщения об ошибках глобально. Вы можете сделать это, отредактировав файл application / langauge / en / validation.php и отредактировав найденный там custom массив:

01
02
03
04
05
06
07
08
09
10
‘custom’ => array(
    ’email_required’ => ‘Please provide an email address’,
    ’email_email’ => ‘Please provide a valid email address’,
    ’email_unique’ => ‘The email address you provided is already being used’,
    ‘password_confirmed’ => ‘Your password confirmation did not match your password.’
);

Библиотека Files Laravel упрощает обработку загрузки файлов с помощью метода Input::upload , который является простой оболочкой для PHP-функции move_uploaded_file :

1
Input::upload(‘input_name’, ‘directory/to/save/file’, ‘filename.extension’);

Для проверки загрузки файлов вы можете использовать библиотеку Validator мы обсуждали выше, например:

1
2
3
4
5
6
7
8
9
$input = array(
    ‘upload’ => Input::file(‘upload’)
);
 
$rules = array(
    ‘upload’ => ‘mimes:zip,rar|max:500’
);
 
$validator = Validator::make($input, $rules);

Библиотека Files также имеет несколько методов манипулирования файлами, например:

1
2
3
4
5
6
7
8
//Get a file
$data = File::get(‘path/file.extension’);
 
//Write a file
File::put(‘path/file.extension’, $data);
 
//Appending to a file
File::append(‘path/file.extension’, $data);

Laravel также предоставляет некоторые общие функции, связанные с файлами, которые можно использовать в вашем коде. Например, метод File::extension возвращает расширение строки имени файла:

1
2
//This will return ‘zip’
File::extension(‘data.zip’);

Функция File::is проверяет, принадлежит ли файл определенного типа. Обратите внимание, что это не просто проверяет расширение файла, но использует расширение Fileinfo PHP для чтения фактического содержимого файла. Это полезно для определения того, что файл действительно имеет правильный тип файла:

1
2
//Returns true if the file is a zip file, false if otherwise
File::is(‘zip’, ‘path/file.zip’);

Список совместимых расширений можно увидеть в файле application / config / mimes.php .

Говоря о типах MIME, вы также можете использовать функцию File::mime для получения MIME-типов расширения. Возвращаемый тип mime основан на том же файле mimes.php :

1
2
//This will return image/png
File::mime(‘png’)

File::cpdir и File::rmdir могут копировать и удалять каталог соответственно.

1
2
3
4
File::cpdir(‘directory/to/copy’, ‘destination/directory’);
 
//File::rmdir is a recursive delete, so it will delete all files and folders inside the directory.
File::rmdir(‘directory/to/delete’);

Теперь, когда мы узнали все о фильтрах , библиотеке валидации и библиотеке файлов , давайте реализуем их в нашем приложении Instapics .


Instapics

Давайте начнем с того, что наши пользователи смогут видеть только аутентифицированные страницы, создав фильтр авторизации, который запускается перед всеми запросами. Поскольку мы используем маршрутизацию на основе контроллера, нам необходимо настроить наши фильтры в нашем контроллере. Давайте поместим фильтры в метод __construct Base_Controller чтобы убедиться, что фильтр auth работает на всех контроллерах, которые его расширяют. Пока мы это делаем, давайте добавим nonauth фильтр, чтобы люди могли посещать только определенные страницы, когда они не nonauth проверку подлинности:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Base_Controller extends Controller {
 
   public function __construct()
   {
       //Assets
       Asset::add(‘jquery’, ‘js/jquery-1.7.2.min.js’);
       Asset::add(‘bootstrap-js’, ‘js/bootstrap.min.js’);
       Asset::add(‘bootstrap-css’, ‘css/bootstrap.min.css’);
       Asset::add(‘bootstrap-css-responsive’, ‘css/bootstrap-responsive.min.css’, ‘bootstrap-css’);
       Asset::add(‘style’, ‘css/style.css’);
       parent::__construct();
 
       //Filters
       $class = get_called_class();
       switch($class) {
           case ‘Home_Controller’:
               $this->filter(‘before’, ‘nonauth’);
               break;
            
           case ‘User_Controller’:
               $this->filter(‘before’, ‘nonauth’)->only(array(‘authenticate’));
               $this->filter(‘before’, ‘auth’)->only(array(‘logout’));
               break;
                
           default:
               $this->filter(‘before’, ‘auth’);
               break;
       }
   }

Здесь мы определяем, что для любых запросов к home маршруту потребуется неаутентифицированный пользователь, что хорошо, поскольку именно здесь находится экран входа в систему. Любой другой запрос по умолчанию будет требовать аутентифицированного пользователя. Для User_Controller у нас фактически есть два отдельных метода, которые требуют как неаутентифицированных пользователей (аутентификация), так и аутентифицированных пользователей (выход из системы), поэтому мы используем only метод, чтобы указать, к каким действиям контроллера применяются фильтры.

Теперь откройте application / rout.php , где мы определим фильтры auth и nonauth . Обратите внимание, что у вас уже может быть существующее определение фильтра auth поэтому просто замените его на приведенное ниже:

1
2
3
4
5
6
7
8
9
Route::filter(‘auth’, function()
{
    if (Auth::guest()) return Redirect::to(‘home’);
});
 
Route::filter(‘nonauth’, function()
{
    if (Auth::guest() == false) return Redirect::to(‘dashboard’);
});

В фильтре auth мы проверяем, прошел ли пользователь аутентификацию с помощью библиотеки Auth . Если пользователь не аутентифицирован, мы перенаправляем его обратно на home маршрут, где находится экран входа, в противном случае ему разрешается продолжить. То же самое с фильтром nonauth — проверьте, аутентифицирован ли пользователь, если он есть, затем перенаправьте его на панель мониторинга.


Теперь, когда мы знаем немного больше о том, как обрабатывать загрузку файлов в Laravel, давайте начнем реализовывать одну из основных функций Instapics — загрузку фотографий. Начните с создания папки с именем application / views / plugins и внутри нее создайте файл представления Blade с именем upload_modal.blade.php . Вставьте следующий HTML-код:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<div class=»modal hide» id=»upload_modal»>
    <div class=»modal-header»>
        <button type=»button» class=»close» data-dismiss=»modal»>&times;</button>
        <h3>Upload a new Instapic</h3>
    </div>
    <div class=»modal-body»>
        <form method=»POST» action=»{{ URL::to(‘photo/upload’) }}» id=»upload_modal_form» enctype=»multipart/form-data»>
            <label for=»photo»>Photo</label>
            <input type=»file» placeholder=»Choose a photo to upload» name=»photo» id=»photo» />
            <label for=»description»>Description</label>
            <textarea placeholder=»Describe your photo in a few sentences» name=»description» id=»description» class=»span5″></textarea>
        </form>
    </div>
    <div class=»modal-footer»>
        <a href=»#» class=»btn» data-dismiss=»modal»>Cancel</a>
        <button type=»button» onclick=»$(‘#upload_modal_form’).submit();»
    </div>
</div>

Давайте запустим эту модальную форму кнопкой — добавьте это в application / views / layouts / main.blade.php после div .nav-collapse :

01
02
03
04
05
06
07
08
09
10
11
12
<div class=»nav-collapse»>
    <ul class=»nav»>
        @section(‘navigation’)
        <li class=»active»><a href=»home»>Home</a></li>
        @yield_section
    </ul>
</div><!—/.nav-collapse —>
@section(‘post_navigation’)
@if (Auth::check())
    @include(‘plugins.loggedin_postnav’)
@endif
@yield_section

Здесь мы включаем файл представления с именем loggedin_postnav если пользователь вошел в систему. Здесь мы добавим кнопку для модальной формы загрузки. В том же файле добавьте это после div .container :

01
02
03
04
05
06
07
08
09
10
11
12
<div class=»container»>
    @yield(‘content’)
    <hr>
    <footer>
    <p>&copy;
    </footer>
</div> <!— /container —>
@section(‘modals’)
@if (Auth::check())
    @include(‘plugins.upload_modal’)
@endif
@yield_section

Здесь мы включаем HTML upload_modal . Тем не менее, мы должны убедиться, что пользователь не вошел в систему, прежде чем включать этот HTML-файл, поскольку, как и триггер кнопки, это действительно не потребуется, если пользователь не аутентифицирован.

Теперь создайте приложение / views / plugins / loggedin_postnav.blade.php

1
2
3
<div class=»btn-group pull-right»>
    <button type=»button» class=»btn btn-primary» onclick=»$(‘#upload_modal’).modal({backdrop: ‘static’});»><i class=»icon-plus-sign icon-white»></i> Upload Instapic</button>
</div>

Обновите страницу, и вы должны увидеть новую кнопку загрузки — нажмите на нее, чтобы увидеть, что она работает!

Загрузить Instapic

Теперь, когда у нас есть работающий интерфейс, давайте начнем работать с серверной частью формы. Создайте приложение / controllers / photo.php и вставьте следующий код для контроллера:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Photo_Controller extends Base_Controller
{
    public function action_upload()
    {
        $input = Input::all();
        $extension = File::extension($input[‘photo’][‘name’]);
        $directory = path(‘public’).’uploads/’.sha1(Auth::user()->id);
        $filename = sha1(Auth::user()->id.time()).».{$extension}»;
 
        $upload_success = Input::upload(‘photo’, $directory, $filename);
         
        if( $upload_success ) {
            Session::flash(‘status_success’, ‘Successfully uploaded new Instapic’);
        } else {
            Session::flash(‘status_error’, ‘An error occurred while uploading new Instapic — please try again.’);
        }
         
        if( $upload_success ) {
            $photo = new Photo(array(
                ‘location’ => URL::to(‘uploads/’.sha1(Auth::user()->id).’/’.$filename),
                ‘description’ => $input[‘description’]
            ));
            Auth::user()->photos()->insert($photo);
        }
         
        return Redirect::to(‘dashboard’);
    }
}

Попробуйте — вы сможете начать загружать новые Instapics.

Давайте добавим несколько правил проверки, чтобы убедиться, что пользователь отправляет только правильные данные. Обновите контроллер следующим:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Photo_Controller extends Base_Controller
{
    public function action_upload()
    {
        $input = Input::all();
         
        if( isset($input[‘description’]) ) {
            $input[‘description’] = filter_var($input[‘description’], FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
        }
 
        $rules = array(
            ‘photo’ => ‘required|image|max:500’, //photo upload must be an image and must not exceed 500kb
            ‘description’ => ‘required’ //description is required
        );
 
        $validation = Validator::make($input, $rules);
 
        if( $validation->fails() ) {
            return Redirect::to(‘dashboard’)->with_errors($validation);
        }
 
        $extension = File::extension($input[‘photo’][‘name’]);
        $directory = path(‘public’).’uploads/’.sha1(Auth::user()->id);
        $filename = sha1(Auth::user()->id.time()).».{$extension}»;
 
        $upload_success = Input::upload(‘photo’, $directory, $filename);
         
        if( $upload_success ) {
            $photo = new Photo(array(
                ‘location’ => URL::to(‘uploads/’.sha1(Auth::user()->id).’/’.$filename),
                ‘description’ => $input[‘description’]
            ));
            Auth::user()->photos()->insert($photo);
            Session::flash(‘status_success’, ‘Successfully uploaded your new Instapic’);
        } else {
            Session::flash(‘status_error’, ‘An error occurred while uploading your new Instapic — please try again.’);
        }
        return Redirect::to(‘dashboard’);
    }
}

Посмотрите, как мы проверяем ввод? Мы удостоверяемся, что фотография присутствует, изображение и меньше, чем 500kb. Мы также следим за тем, чтобы описание присутствовало после санации. Мы пока не сможем увидеть наши сообщения об ошибках, поэтому давайте исправим это, добавив немного HTML для отображения наших сообщений об ошибках. Откройте application / views / layouts / main.blade.php и добавьте следующее в div .container :

1
2
3
4
5
6
7
8
<div class=»container»>
    @include(‘plugins.status’)
    @yield(‘content’)
    <hr>
    <footer>
    <p>&copy;
    </footer>
</div> <!— /container —>

Теперь создайте приложение / views / plugins / status.blade.php . Это где мы будем отображать фактические сообщения об ошибках. Мы также добавим поддержку сообщений о состоянии сеанса (например, тот, который мы используем при проверке $upload_success в коде контроллера Photos ):

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@if (isset($errors) && count($errors->all()) > 0)
<div class=»alert alert-error»>
    <a class=»close» data-dismiss=»alert» href=»#»>×</a>
    <h4 class=»alert-heading»>Oh Snap!</h4>
    <ul>
    @foreach ($errors->all(‘<li>:message</li>’) as $message)
    {{ $message }}
    @endforeach
    </ul>
</div>
@elseif (!is_null(Session::get(‘status_error’)))
<div class=»alert alert-error»>
    <a class=»close» data-dismiss=»alert» href=»#»>×</a>
    <h4 class=»alert-heading»>Oh Snap!</h4>
    @if (is_array(Session::get(‘status_error’)))
        <ul>
        @foreach (Session::get(‘status_error’) as $error)
            <li>{{ $error }}</li>
        @endforeach
        </ul>
    @else
        {{ Session::get(‘status_error’) }}
    @endif
</div>
@endif
 
@if (!is_null(Session::get(‘status_success’)))
<div class=»alert alert-success»>
    <a class=»close» data-dismiss=»alert» href=»#»>×</a>
    <h4 class=»alert-heading»>Success!</h4>
    @if (is_array(Session::get(‘status_success’)))
        <ul>
        @foreach (Session::get(‘status_success’) as $success)
            <li>{{ $success }}</li>
        @endforeach
        </ul>
    @else
        {{ Session::get(‘status_success’) }}
    @endif
</div>
@endif

Попробуйте вызвать ошибки в форме загрузки прямо сейчас, отправив файл без выбора или без описания (так как оба требуются). Вы должны увидеть сообщения об ошибках, отображаемые сверху:

Неопределенные ошибки

Теперь, когда мы знаем, как использовать библиотеку Laravel Validation , давайте вернемся к нашей первой форме — форме входа и регистрации. На данный момент мы просто используем echo чтобы увидеть, что вход в систему или регистрация не пройдены — давайте заменим это на правильную проверку. Откройте application / controllers / user.php и обновите его так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class User_Controller extends Base_Controller
{
    public function action_authenticate()
    {
        $email = Input::get(’email’);
        $password = Input::get(‘password’);
        $new_user = Input::get(‘new_user’, ‘off’);
         
        $input = array(
            ’email’ => $email,
            ‘password’ => $password
        );
         
        if( $new_user == ‘on’ ) {
             
            $rules = array(
                ’email’ => ‘required|email|unique:users’,
                ‘password’ => ‘required’
            );
             
            $validation = Validator::make($input, $rules);
             
            if( $validation->fails() ) {
                return Redirect::to(‘home’)->with_errors($validation);
            }
             
            try {
                $user = new User();
                $user->email = $email;
                $user->password = Hash::make($password);
                $user->save();
                Auth::login($user);
             
                return Redirect::to(‘dashboard’);
            } catch( Exception $e ) {
                Session::flash(‘status_error’, ‘An error occurred while creating a new account — please try again.’);
                return Redirect::to(‘home’);
            }
        } else {
         
            $rules = array(
                ’email’ => ‘required|email|exists:users’,
                ‘password’ => ‘required’
            );
             
            $validation = Validator::make($input, $rules);
             
            if( $validation->fails() ) {
                return Redirect::to(‘home’)->with_errors($validation);
            }
             
            $credentials = array(
                ‘username’ => $email,
                ‘password’ => $password
            );
            if( Auth::attempt($credentials)) {
                return Redirect::to(‘dashboard’);
            } else {
                Session::flash(‘status_error’, ‘Your email or password is invalid — please try again.’);
                return Redirect::to(‘home’);
            }
        }
    }
     
    public function action_logout()
    {
        Auth::logout();
        Redirect::to(‘home/index’);
    }
}

Поскольку мы сделали наши сообщения о статусе модульными, нам даже не нужно писать дополнительный HTML, чтобы увидеть сообщения об ошибках в действии! Просто попробуйте!

Неопределенные ошибки

В третьем уроке из нашей серии Laravel мы узнали:

  • Как, когда и где использовать Laravel Filters
  • Как использовать библиотеку валидации Laravel и как обрабатывать ошибки библиотеки валидации .
  • Как управлять файлами в Laravel с помощью библиотеки Files

Laravel поставляется с множеством этих небольших функций и библиотек, которые, хотя и реализуются другими способами, становятся проще и проще (например, загрузка файлов в одну строку!) Благодаря использованию выразительной природы Laravel. Именно эти небольшие, экономящие время библиотеки добавляют и со временем экономят массу потраченного времени на переписывание кода.

Далее в наших веб-приложениях из серии Scratch with Laravel мы узнаем больше о событиях, миграциях и некотором расширенном использовании Eloquent ORM!

Что вы думаете о библиотеках Laravel, обсуждаемых в руководстве? Это то, что вы считаете полезным? Дай мне знать в комментариях! И, если вы являетесь участником Tuts + Premium , следите за обновлениями нашего предстоящего курса Laravel Essentials!