Основы Laravel 8

Содержание

Laravel — это фреймворк для веб-приложений с выразительным элегантным синтаксисом. Мы уже заложили основу — даем вам возможность творить, не беспокоясь о мелочах.

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

Создавайте надежные приложения с полным стеком на PHP, используя Laravel и Livewire. Любите JavaScript? Создайте монолитный интерфейс на основе React или Vue, объединив Laravel с Inertia.

Или позвольте Laravel служить надежным внутренним API для вашего приложения Next.js, мобильного приложения или другого внешнего интерфейса. В любом случае, наши стартовые комплекты помогут вам продуктивно работать за считанные минуты.

Файловая структура Laravel

  • App: эта папка является ядром приложения и содержит основной код.
    • Console: эта папка содержит все пользовательские команды Artisan, созданные с помощью make: command
    • Exceptions: эта папка содержит обработчик исключений приложения. Это хорошее место для добавления пользовательских классов исключений, чтобы обработать различные исключения, создаваемые вашим приложением.
    • Http: этот каталог содержит все ваши контроллеры, промежуточное программное обеспечение и запросы.
    • Models: это новая папка, добавленная в версии Laravel 8 для хранения файлов моделей. Раньше модели хранились в папке App, но теперь их можно хранить и в папках App / Models.
    • Providers: эта папка содержит всех поставщиков услуг для вашего приложения. Вы можете узнать больше о поставщиках услуг здесь.
  • Bootstrap: эта папка содержит загрузочную программу фреймворка и файлы конфигурации. Она также содержит папку с файлами кеша, сгенерированными фреймворком.
  • Config: эта папка содержит все файлы конфигурации вашего приложения.
  • Database: эта папка содержит все миграции и начальные данные базы данных. Вы также можете хранить здесь файлы базы данных SQLite.
  • Public: эта папка содержит такие ресурсы, как изображения, JavaScript и CSS-файлы.
  • Resources: эта папка содержит все файлы представления, а также файлы CSS, LESS и SASS. Здесь также находится папка lang для хранения языковых файлов.
  • Routes: эта папка содержит все маршруты приложения, а файл php получает все запросы к вашему приложению, и здесь вы можете перенаправить запросы на соответствующие методы контроллера.
  • Storage: эта папка содержит все шаблоны Blade, файлы сеансов, файлы кеша и другие.
  • Tests: эта папка содержит все тестовые файлы.
  • Vendor: эта папка содержит все Composer-зависимости.

Роутинг в Laravel

Основной файл роутов находится в файле /routes/web.php

При определении нескольких маршрутов, которые используют один и тот же URI, маршруты, использующие методы get, post, put, patch, delete и options, должны быть определены перед маршрутами, использующими методы any, match и redirect. Это гарантирует, что входящий запрос соответствует правильному маршруту.

Это объясняется тем, что фреймворк останавливается на том маршруте где было найдено первое совпадении.

В данном файле изначально находится только один маршрут. Здесь идет обращение к классу/фасаду Route. У класса Route есть ряд методов, в данном коде мы видем метод get. Метод get принимает два параметра. Первый параметр это строка uri - это часть адреса url которая будет соответствовать коду выполняемому вторым параметром . В данном случае это callback функция которая возвращает view('welcome')

Route::get('/', function () {
	return view('welcome');
});

Кроме callback функции вторым параметром может быть название Контроллера и метода котоый необходимо вызвать или в который нужно передать запрос.

Передача параметров в представление

Так же мы может передать переменную в представление (view) welcome.

Route::get('/', function () {
	$result = 2 + 3;
	return view('welcome')->with('variable', $result);
});

Значение переменной $result можно вывести в представлении <?= $variable ?> Так же мы можем вывести переменную следующим образом {{ $variable }}

Второй вариант передачи параметров - это массив:

Route::get('/', function () {
	$result = 2 + 3;
	return view('welcome', ['variable' => $result]);
});

Так же есть способ передать зачения нативной php функцией compact:

Route::get('/', function () {
	$result = 2 + 3;
	return view('welcome', compact('result'));
});

Всего доступно 6 методов отвечающие на любой HTTP-метод:

Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);

Иногда требуется зарегистрировать маршрут, отвечающий на несколько HTTP-методов. Вы можете сделать это с помощью метода match. Или вы даже можете зарегистрировать маршрут, отвечающий на все HTTP-методы, используя метод any:

Route::match(['get', 'post'], '/', function () {
    //
});

Route::any('/', function () {
    //
});

Именованные маршруты

Именованные маршруты позволяют легко создавать URL-адреса или перенаправления для определенных маршрутов. Вы можете указать имя для маршрута, связав метод name с определением маршрута:

Route::get('/user/profile', function () {
    //
})->name('profile');

Вы также можете указать имена маршрутов для действий контроллера:

Route::get(
    '/user/profile',
    [UserProfileController::class, 'show']
)->name('profile');

Для получения полного url адреса маршрута в представлении, можно воспользоваться следующим кодом - {{ route('profile') }}

Редиректы

К примеру нужно сделать перенаправление со страницы about на страницу contact:

Route::redirect('about', 'contact');

Теперь при обращении к странице about будет перенаправления на страницу contact со статусом 302. Это означает, что ресурс был временно перемещен по новому адресу.

К примеру мы хотим отправлять другой статус/код ответа. Тогда нужно передать код третьим параметром:

Route::redirect('about', 'contact', 301);

Обязательные параметры

Иногда бывает необходимым отслеживание сегментов URI в вашем маршруте. Например, может потребоваться отследить идентификатор пользователя из URL-адреса. Это можно сделать указав параметры маршрута:

Route::get('/user/{id}', function ($id) {
    return 'User '.$id;
});

Так же можно определить столько параметров маршрута, сколько потребуется для маршрута:

Route::get('/posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});

Параметры маршрута всегда заключаются в фигурные скобки {} и должны состоять из буквенных символов. Подчеркивание (_) также допускается в именах параметров маршрута. 

Необязательные параметры

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

Route::get('/user/{name?}', function ($name = null) {
    return $name;
});

Route::get('/user/{name?}', function ($name = 'John') {
    return $name;
});

Ограничения с помощью регулярного выражения

Можно ограничить формат параметров маршрута, используя метод where экземпляра маршрута. Метод where принимает имя параметра и регулярное выражение, определяющее, как параметр должен быть ограничен:

Route::get('/user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');

Route::get('/user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');

Route::get('/user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

Глобальные ограничения регулярным выражением

Чтобы параметр маршрута всегда ограничивался конкретным регулярным выражением, можно использовать метод pattern. Шаблон определяется в методе boot класса App\Providers\RouteServiceProvider:

public function boot()
{
    Route::pattern('id', '[0-9]+');
}

Как только шаблон определен, он автоматически применяется ко всем маршрутам, использующим это имя параметра:

Route::get('/user/{id}', function ($id) {
    // Выполнится, только если параметр `{id}` имеет числовое значение ...
});

Префиксы URI сгруппированных маршрутов

Метод prefix используется для подстановки указанного URI в качестве префикса каждому маршруту в группе. Например, можно подставить префикс admin перед всеми URI сгруппированных маршрутов:

Route::prefix('admin')->group(function () {
    Route::get('/users', function () {
        // Соответствует URL-адресу `/admin/users` ...
    });
});

Префиксы имен сгруппированных маршрутов

Метод name используется для подстановки указанной строки в качестве префикса имени каждому маршруту в группе.

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

Route::name('admin.')->group(function () {
    Route::get('/users', function () {
        // Маршруту присвоено имя `admin.users` ...
    })->name('users');
});

Подмена методов формы

HTML-формы не поддерживают действия PUTPATCH или DELETE. Таким образом, при определении маршрутов PUTPATCH или DELETE, которые вызываются из HTML-формы, вам нужно будет добавить в форму скрытое поле _method. Значение, отправленное с полем _method, будет использоваться как метод HTTP-запроса:

<form action="/example" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>

Для удобства вы можете использовать директиву @method шаблонизатора Blade для создания поля ввода _method:

<form action="/example" method="POST">
    @method('PUT')
    @csrf
</form>

Резервные маршруты

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

Как правило, необработанные запросы автоматически отображают страницу 404 через обработчик исключений приложения. Однако, обычно резервный маршрут определяется в файле routes/web.php, то все посредники группы web будет применены к этому маршруту. При необходимости можно добавить дополнительный посредник для этого маршрута:

Route::fallback(function () {
    return redirect()->route('home');
});

Резервный маршрут всегда должен быть последним зарегистрированным маршрутом в приложении.

Так же мы можем создать свой редирект, указав код ошибки и перенаправить на отдельный view файл для этой ошибки с помощью функции abort().

Route::fallback(function () {
    abort(404, 'Oops! Page not found...');
});

В нашем случае это ошибка 404:

 /resources/views/errors/404.blade.php

Для получения текста ошибки Oops! Page not found… в файле 404.blade.php нужно написать следующий код:

{{ $exception->getMessage() }}

Контроллеры

Вместо того чтобы определять всю логику обработки запросов в файлах маршрутов таких как web.php, можно организовать это поведение с помощью классов «контроллеров».

Контроллеры могут сгруппировать связанную логику обработки запросов в один класс. Например, класс UserController может обрабатывать все входящие запросы, относящиеся к пользователям, включая отображение, создание, обновление и удаление пользователей. По умолчанию контроллеры хранятся в каталоге app/Http/Controllers.

Создание контроллера

Создадим первый контроллер HomeController.php:

class HomeController extends Controller
{
    public function index()
    {
        return 'Hello world';
    }
}

Для того, что бы метод/экшен index() был доступен с главной страницы, напишем следующий rout в файле web.php

Route::get('/', [HomeController::class, 'index']);

Передача данных в представление

Создадим представление resources/views/home.blade.php и передадим в него данные через контроллер HomeController:

class HomeController extends Controller
{
    public function index()
    {
        return view('home', ['result' => '5']);
    }
}

Для получения переменной result в файле home.blade.php напишет этот код:

{{ $result }}

Создадим еще один контроллер PageController:

class PageController extends Controller
{
    public function show()
    {
        return view('pages.about');
    }
}

Так же создадим представление resources/views/pages/about.blade.php. Как видно из кода выше для доступа к файлу представления который находится в папке pages мы используем . - точку.

Для получения доступа к этому представлению по адресу website.com/page/about напишем в файле роутов web.php следующий код:

Route::get('page/about', [PageController::class, 'show']);

Динамический slug

Для создания динамического слага изменим роут и вмето about напишем {slug}:

Route::get('page/{slug}', [PageController::class, 'show']);

Так же в контроллере PageController изменим код. Добавил в метод show() аргумент $slug и используем ее - view("pages.$slug")

class PageController extends Controller
{
    public function show($slug)
    {
        return view("pages.$slug");
    }
}

Очевидно, что если слаг - about, то будет подключатся представление resources/views/pages/about.blade.php

Ресурсные контроллеры

Если думать о каждой модели Eloquent в приложении как о «ресурсе», то для каждого ресурса в вашем приложении обычно выполняются одни и те же наборы действий. Например, представьте, что приложение содержит модель Post. Вполне вероятно, что пользователи могут создавать, читать, обновлять или удалять эти ресурсы.

Благодаря такому распространенному варианту использования, маршрутизация ресурсов Laravel присвоит типичные маршруты создания, чтения, обновления и удаления «CRUD» контроллеру с помощью одной строки кода.

Для начала мы можем использовать параметр --resource команды make:controller, чтобы быстро создать контроллер для обработки этих действий:

php artisan make:controller PostController --resource

Эта команда поместит новый класс контроллера в каталог app/Http/Controllers. Контроллер будет содержать метод для каждого из доступных действий с ресурсами. Затем нужно зарегистрировать маршрут ресурса в файле web.php который указывает на контроллер:

Route::resource('post', PostController::class);

Действия ресурсного контроллера

МетодURIДействиеИмя маршрута
GET/postsindexposts.index
GET/posts/createcreateposts.create
POST/postsstoreposts.store
GET/posts/{post}showposts.show
GET/posts/{post}/editeditposts.edit
PUT/PATCH/posts/{post}updateposts.update
DELETE/posts/{post}destroyposts.destroy

Сделаем маршрут для нашего ресурсного контроллера PostController:

Route::resource('posts', PostController::class);

Обратите внимание, что для ресурсного контроллера указывается только класс контроллера, без указания его методов.

Метод create

Создадим представления create.blade.php

<form action="{{ route('posts.store') }}" method="post">
    @csrf

    <input type="text" name="title">
    <button type="submit">Submit</button>
</form>

В файле контроллера PostController, в методе create() подключим представление create.blade.php:

class PostController extends Controller
{
    public function index()
    {
        return view('posts.index');
    }

    public function create()
    {
        return view('posts.create');
    }

    public function store(Request $request)
    {
        //
    }

    public function show($id)
    {
        //
    }

    public function edit($id)
    {
        //
    }

    public function update(Request $request, $id)
    {
        //
    }

    public function destroy($id)
    {
        //
    }
}

Метод store

Далее нам нужно принимать данные из представления create.blade.php. Принимать его будем в методе store контроллера PostController. Но на данном этапе мы просто выведем данные который отправим из формы:

public function store(Request $request)
{
    dd($request);
}

Получим следующий результат:

Здесь мы получаем распечатанный объект Request.

Данные из формы

Метод show

Добавим код в метод show() в контроллере PostController:

public function show($id)
{
    return "Post $id";
}

Создадим представление index.blade.php:

<h1>Список постов</h1>

<ul>
    <li>
        <a href="{{ route('posts.show',  ['post' => 1]) }}">Post 1</a>
        <a href="{{ route('posts.edit',  ['post' => 1]) }}">Edit</a>
    </li>

</ul>
При переходе по ссылке Post 1 попадаем в posts/show

Метод edit

Данный метод предназначен для редактирования данных. Создадим представление resources/views/posts/edit.blade.php:

<form action="{{ route('posts.update', ['post' => $id]) }}" method="post">
    @csrf
    @method('PUT')
    <input type="text" name="title">
    <button type="submit">Submit</button>
</form>

Для обновления данных используется метод PUT/PATCH, один из этих методов нужно указать с помощью скрытого поля <input> или использовать возможность шаблонизатора blade и написать следующий код внутри формы @method('PUT'). Данные уходят на маршрут update, по этому в action пишем posts.update

Теперь подключим это представление в PostController:

public function edit($id)
{
    return view('posts.edit', ['id' => $id]);
}

Метод update

public function update(Request $request, $id)
{
    dump($id);
    dd($request);
}
Вывод $request из формы представления edit

Метод delete

Для метода delete() необходима форма. Добавим форму в представление index.blade.php

<h1>Список постов</h1>

<ul>
    <li>
        <a href="{{ route('posts.show',  ['post' => 1]) }}">Post 1</a>
        <a href="{{ route('posts.edit',  ['post' => 1]) }}">Edit</a>
        <form action="{{ route('posts.destroy', ['post' => 1]) }}" method="post">
            @csrf
            @method('DELETE')
           <button type="submit">Delete</button>
        </form>
    </li>
</ul>

После нажатия на кнопку Delete мы попадаем в метод destroy() контроллера PostController и дальше пишем необходимую логику.

Консольные команды

Artisan – это интерфейс командной строки, входящий в состав Laravel. Он предлагает ряд полезных команд, которые помогут при создании приложения. Для просмотра списка всех доступных команд Artisan можно использовать команду list:

php artisan list

Каждая команда также включает в себя экран «справки», который отображает и описывает доступные аргументы и параметры команды. Чтобы просмотреть экран справки, используйте help перед именем команды:

php artisan help make:controller

Команды make консоли Artisan

Команды make консоли Artisan используются для создания различных классов, таких как контроллеры, задания, миграции и тесты. Эти классы создаются с помощью файлов «заготовок», которые заполняются значениями на основе ваших входных данных.

Команды make консоли Artisan
Команды make консоли Artisan

Создание контроллера

php artisan make:controller PageController

Миграции

Миграции похожи на контроль версий для вашей базы данных, позволяют вашей команде определять схемы базы данных приложения и совместно использовать их определение.

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

Генерация миграции

Чтобы сгенерировать новую миграцию базы данных, используйте команду make:migration.

Эта команда поместит новый класс миграции в каталог database/migrations вашего приложения. Каждое имя файла миграции содержит временную метку, которая позволяет Laravel определять порядок применения миграций:

php artisan make:migration create_posts_table

Напишем следующий код в созданной миграции CreatePostsTable:

class CreatePostsTable extends Migration
{
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->increments('id');
            $table->string('title');
            $table->text('content');
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

Изменение данных в таблице

Создадим новую миграцию для изменения столбцов с ключом --table=posts:

php artisan make:migration change_posts_table --table=posts

Для изменения свойств столбцов в таблице posts напишем следующий код в миграции ChangePostsTable:

class ChangePostsTable extends Migration
{
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->string('title', 100)->change();
            $table->string('content')->nullable()->change();
        });
    }

    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->string('title')->change();
            $table->string('content')->nullable(false)->change();
        });
    }
}

Стоит обратить внимание, что в данной миграции используется Schema::table, а не Schema::create, как в первой миграции где мы создавали таблицу.

Рассмотрим часть кода миграции ChangePostsTable:

  $table->string('title', 100)->change();

Для того, что бы изменения применились, нужно вызвать метод change(). Посмотреть все модификаторы столбцов можно в официальной документации.

Выполнение SQL-запросов

Почти каждое современное веб-приложение взаимодействует с базой данных. Laravel делает взаимодействие с базами данных чрезвычайно простым через поддержку множества баз данных, используя либо сырой SQL построитель запросов, либо Eloquent ORM

После того как соединение с базой данных настроено, можно выполнять запросы, используя фасад DB. Фасад DB содержит методы для каждого типа запроса: selectupdateinsertdelete, и statement.

Метод select

Добавим следующий код в HomeController для выборы всех постов из таблицы:

class HomeController extends Controller
{
    public function index()
    {
        $posts = DB::select("SELECT * FROM posts");

        return $posts;
    }
}

Получим результат:

Ответ в виде массива данных в формате JSON

Метод insert

Добавим следующий код в HomeController для добавления данных в таблицу используя подстановку позиционных аргументов:

class HomeController extends Controller
{
    public function index()
    {
        $query = DB::insert("INSERT INTO posts (title, content) VALUES (?, ?)", ['Статья 3', 'Контент статьи 3']);

        var_dump($query);
    }
}

Данный запрос вернет bool(true) или bool(false) в случае ошибки.

Метод update

Обновим данные статьи с id равным 3 используя именованные аргументы:

class HomeController extends Controller
{
    public function index()
    {
        $query = DB::insert("INSERT INTO posts (title, content) VALUES (?, ?)", ['Статья 3', 'Контент статьи 3']);

        var_dump($query);
    }
}

Если запрос пройдет успешно, то метод вернет количество измененных строк, в данном случае insert() вернет int(1).

Метод delete

Удалим строку с id равным 3 используя позиционные элементы аргументы:

class HomeController extends Controller
{
    public function index()
    {
        $query = DB::delete("DELETE FROM posts WHERE id =:id", ['id' => 3]);

        var_dump($query);
    }
}

Если запрос пройдет успешно, то метод вернет количество измененных строк, в данном случае insert() вернет int(1) аналогично методу update().

Выполнение запроса общего типа

Некоторые операторы базы данных не возвращают никакого значения. Для этих типов операций используется метод statement фасада DB:

DB::statement('DROP TABLE posts');

Механизм транзакций

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

DB::transaction(function () {
    DB::update('UPDATE posts SET votes = 1');
    DB::delete('DELETE FROM posts');
});

Использование транзакций вручную

Если нужно вручную начать транзакцию и иметь полный контроль над откатами и фиксациями, то можно использовать методы beginTransaction(), commit() и rollBack() фасада DB:

    public function index()
    {
        DB::beginTransaction();
        try {
            DB::update("UPDATE posts SET created_at = ? WHERE created_at IS NULL", [NOW()]);
            DB::update("UPDATE posts SET updated_at = ? WHERE updated_at IS NULL", [NOW()]);
            DB::commit();
        } catch (Exception $exception) {
            DB::rollBack();
            echo $exception->getMessage();
        }
    }
}

Конструктор запросов

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

Построитель запросов Laravel использует связывание параметров PDO для защиты приложения от SQL-инъекций. Нет необходимости чистить строки, передаваемые как связываемые параметры.

В данном разделе для примера будет работа с базой данных world от Mysql. Скачать базу данных можно по этой ссылке.

Метод get

Сделаем выборку из таблицы country. Для осуществления выборки нужно использовать метод - get()

class HomeController extends Controller
{
    public function index()
    {
        $data = DB::table('country')->get();

        return $data;
    }
}

Методы select и limit

Ограничим выборку с помощью метода limit(), так же выберем столбцы Code и Name используя метод select():

class HomeController extends Controller
{
    public function index()
    {
        $data = DB::table('country')
                  ->select('Code', 'Name')
                  ->limit(5)
                  ->get();

        return $data;
    }
}

Метод orderBy

Сделаем сортировку по убыванию используя метод orderBy() с выбором только одной записи используя метод first():

class HomeController extends Controller
{
    public function index()
    {
        $data = DB::table('country')
                  ->select('Code', 'Name')
                  ->orderBy('Code', 'ASC')
                  ->first();

        return $data;
    }
}

В метод orderBy() передаем два аргумента - это поле по которому будет сортировка и второе это тип сортировки ASC и DESC. Обратите внимание что для метода first() не нужно использовать метод get().

Метод find

Получим одну строку по значению столбца id:

{
    public function index()
    {
        $data = DB::table('city')
                  ->select('ID', 'Name')
                  ->find(1);

        return $data;
    }
}

Метод where

Метод where() использует 3 аргумента. Первый аргумент это - колонка, второй аргумент это - оператор и третий аргумент это - значение:

class HomeController extends Controller
{
    public function index()
    {
        $data = DB::table('city')
                  ->select('ID', 'Name')
                  ->where('id', '=', '2')
                  ->get();

        return $data;
    }
}

Так же можно использовать формат передачи аргументов в виде массива:

class HomeController extends Controller
{
    public function index()
    {
        $data = DB::table('city')
                  ->select('ID', 'Name')
                  ->where([
                      ['id', '>', '5'],
                      ['id', '<', '20'],
                  ])
                  ->get();

        return $data;
    }
}

В таком запросе получим записи с id от 6 до 19 включительно.

Метод value

Получим строковое значение (не массив) колонки Name из таблицы city используя метод value() вместо select():

class HomeController extends Controller
{
    public function index()
    {
        $data = DB::table('city')
                  ->where('id', '<', '5')
                  ->value('Name');

        return $data;
    }
}

Метод value() выбирает только одну запись.

Метод pluck

Метод pluck() возвращает все значения конкретного столбца:

class HomeController extends Controller
{
    public function index()
    {
        $data = DB::table('country')
                  ->pluck('Name');

        return $data;
    }
}

Метод pluck() принимает вторым аргументом значение ключа, если по умолчанию это будет id. Выполнив следующий код, указав ключом столбец code:

class HomeController extends Controller
{
    public function index()
    {
        $data = DB::table('country')
                  ->pluck('Name', 'Code');

        return $data;
    }
}

Получим следующий результат:

Объект в котором ключ это - code и значение это - name

Метод distinct

Метод distinct позволяет возвращать уникальные результаты запроса:

class HomeController extends Controller
{
    public function index()
    {
        $data = DB::table('city')
                  ->select('CountryCode')
                  ->distinct()
                  ->get();

        return $data;
    }
}

Метод join

Построитель запросов также может использоваться для добавления выражений соединения (join) к запросам. Чтобы выполнить базовое «внутреннее соединение» (inner join), можно использовать метод join().

Первым аргументом, передаваемым методу join(), является имя таблицы, к которой нужно присоединиться, а остальные аргументы определяют ограничения столбца для соединения.

Сделаем выборку по городам и странам прикрепленным к ним:

class HomeController extends Controller
{
    public function index()
    {
        $data = DB::table('city')
                  ->select('city.ID', 'city.Name as city_name', 'country.Code', 'country.Name as country_name')
                  ->limit(10)
                  ->join('country', 'city.CountryCode', '=', 'country.Code')
                  ->orderBy('city.ID')
                  ->get();

        return $data;
    }
}

Методы count, max, min, sum, avg

Выедем максимальное, минимальное значение населения, а так же количество стран в таблице country:

class HomeController extends Controller
{
    public function index()
    {
        echo DB::table('country')->count() . PHP_EOL;
        echo DB::table('country')->max('population') . PHP_EOL;
        echo DB::table('country')->min('population') . PHP_EOL;
        // echo DB::table('country')->sum('population') . PHP_EOL;
        // echo DB::table('country')->avg('population') . PHP_EOL;
    }
}

Модель и Eloquent ORM

Laravel содержит ORM-библиотеку Eloquent, предоставляющую способ работы с базой данных, который часто удобнее обычного построителя запросов. При использовании Eloquent каждая таблица БД имеет соответствующую «Модель», которая используется для взаимодействия с этой таблицей.

Помимо получения записей из таблицы БД, модели Eloquent также позволяют вставлять, обновлять и удалять записи из таблицы.

Создание модели с миграцией

php artisan make:model Post --migration

В проекте создался файл app/Models/Post.php и файл миграции database/migrations/2022_12_09_155313_create_posts_table.php

В файле миграции напишем следующий код:

class CreatePostsTable extends Migration
{
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('content');
            $table->timestamps();
        });
    }
    
    public function down()
    {
        Schema::dropIfExists('posts');
    }
}

И выполним миграцию:

php artisan migrate

Eloquent предполагает, что в соответствующей таблице БД каждой модели есть столбец первичного ключа с именем id. Можно определить защищенное свойство $primaryKey в модели, чтобы указать другой столбец, который служит первичным ключом.

Запись в базу данных

Добавим в наш HomeController код который запишет новую строку в базу данных используя модель Post:

class HomeController extends Controller
{
    public function index()
    {
        $post = new Post();
        $post->title = 'Статья 1';
        $post->content = 'Контент статьи 1';
        $post->save();
    }
}

Чтение из базы данных

Поработаем с базой данных world от MySQL. Создадим модель City:

php artisan make:model City  

Создадим модель Country:

php artisan make:model Country  

Использовании нестандартных полей Laravel:

protected $table = 'my_posts'; — нестандартное название таблицы
protected $primaryKey = 'post_id'; — нестандартный первичный ключ
public $incrementing = false; — не инкрементировать автоматический
protected $keyType = 'string'; — id ключи не число
public $timestamps = false; — не использовать created_at и updated_at
protected $attributes = ['content' => 'Lorem…']; — заполняется автоматический

После создания модели добавим этот код в модель City:

class City extends Model
{
    protected $table = 'city';
}

Так как при использовании "соглашений" Laravel наша таблица должна была бы называться citys, но в базе mysql она называется в единственном числе, по этому мы присваиваем нужное название таблицы свойству protected $table.

Так же добавим код в модель Country:

class Country extends Model
{
    protected $table = 'country';
    protected $primaryKey ='code';
    public $incrementing = false;
    protected $keyType = 'string';
}

Что бы получить все записи из таблицы country напишем в HomeController код:

class HomeController extends Controller
{
    public function index()
    {
      $data = Country::all();
    }
}

Мы обращаемся к модели Country и получаем все записи методом all().

Выберем записи по следующим критериям:

class HomeController extends Controller
{
    public function index()
    {
        $data = Country::where('Code', '<', 'ALB')
                       ->select('Code', 'Name')
                       ->offset(1)
                       ->limit(2)
                       ->get();

        dd($data);
    }
}

Теперь выберем из таблицы country записи по столбцу Code:

class HomeController extends Controller
{
    public function index()
    {
        $data = Country::find('AGO');

        dd($data);
    }
}

Middleware

Посредник обеспечивает удобный механизм для проверки и фильтрации HTTP-запросов, поступающих в приложение. В Laravel уже содержится посредник, проверяющий аутентификацию пользователя приложения.

Посредник может быть написан для выполнения различных задач помимо аутентификации. Например, посредник для ведения журнала может регистрировать все входящие запросы приложения.

Несколько вещей, которые можно достичь с помощью middleware:

  • Логирование запросов
  • Перенаправление пользователей
  • Изменение / очистка входящих параметров
  • Манипулирование ответом, созданным приложением Laravel

Эта команда создать файл app/Http/Middleware/AdminMiddleware.php:

php artisan make:middleware AdminMiddleware

Код для AdminMiddleware который делает редирект на главную страницу:

class AdminMiddleware
{
    public function handle(Request $request, Closure $next)
    {
        return redirect()->home();
    }
}

Для работы нашего middleware его необходимо зарегистрировать. В файл /app/Http/Kernel.php нужно добавить этот код:

    protected $routeMiddleware = [
        'admin' => \App\Http\Middleware\AdminMiddleware::class
    ];

Теперь привяжем этот middleware к роуту, откроем файл routes/web.php и добавим следующий код:

Route::get('/admin', [HomeController::class, 'admin'])->middleware('admin');

Теперь при переходе на роут /admin будет срабатывать middleware admin, который делает перенаправление на главную страницу.

Seeding (заполнители)

Laravel предлагает возможность наполнения вашей базы тестовыми данными с использованием классов-наполнителей. Все классы наполнителей хранятся в каталоге database/seeders.

Создание seeder

Чтобы сгенерировать новый наполнитель, используйте команду make:seeder. Эта команда поместит новый класс наполнителя в каталог database/seeders вашего приложения:

php artisan make:seeder PostSeeder

Откроем созданный файл /database/migrations/....._create_posts_table.php Класс наполнителя по умолчанию содержит только один метод: run:

class PostSeeder extends Seeder
{
    public function run()
    {
        DB::table('posts')->insert([
            'title'   => Str::random(5),
            'content' => Str::random(30)
        ]);
    }
}

С помощью фасада DB добавим данные в поля title и content.

Запуск seeder

Нужно выполнить команду db:seed для наполнения базы данных. По умолчанию команда db:seed запускает класс Database\Seeders\DatabaseSeeder, который, в свою очередь, может вызывать другие классы. Однако вы можете использовать параметр --class, чтобы указать конкретный класс наполнителя для его индивидуального запуска:

php artisan db:seed

php artisan db:seed --class=PostSeeder

Обратите внимание, для запуска нашего созданного заполнителя (PostSeeder) командой php artisan db:seed нужно добавить код в файл DatabaseSeeder.php:

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $this->call([
            PostSeeder::class
        ]);
    }
}

И только после этого команда db:seed запустит наш seeder PostSeeder. При таком запуске заполнителя добавиться только 1 строка в базу данных. Для массового заполнения используются фабрики моделей.

Использование фабрик (factory)

Может потребоваться вставить несколько записей в базу данных. Это пример написания фабрики в файле database/factories/UserFactory.php:

class UserFactory extends Factory
{
    public function definition()
    {
        return [
            'name' => $this->faker->name(),
            'email' => $this->faker->unique()->safeEmail(),
            'email_verified_at' => now(),
            'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
            'remember_token' => Str::random(10),
        ];
    }
}

Фабрики – это классы, которые расширяют базовый класс фабрики Laravel и определяют метод definition(). Через свойство $faker фабрики получают доступ к библиотеке Faker PHP, которая позволяет вам удобно генерировать различные виды случайных данных для тестирования.

Генерация фабрик

Для генерации фабрики используйте команду make:factory:

php artisan make:factory PostFactory

Эта команда поместит новый класс фабрики в каталог database/factories. Откроем файл database/factories/PostFactory.php и добавим этот код:

class PostFactory extends Factory
{
    public function definition()
    {
        return [
            'title' => $this->faker->word(),
            'content' => $this->faker->paragraph(1)
        ];
    }
}

Теперь вернёмся в файл заполнителя (seeder) PostSeeder.php и вместо ручного заполнения полей таблицы:

class PostSeeder extends Seeder
{
    public function run()
    {
        'title'   => Str::random(5),
        'content' => Str::random(30)
    }
}

будем использовать созданную фабрику PostFactory:

class PostSeeder extends Seeder
{
    public function run()
    {
        Post::factory()
            ->count(10)
            ->create();
    }
}

Используя трейт HasFactory в модели Post.php вызываем статический метод factory(), с помощью метода count() указываем количество повторений seeder и методом create() выполняем заполнение.

Заполняем базу с помощью команды:

php artisan db:seed

Аксессоры и Мутаторы

Аксессоры, мутаторы и приведение атрибутов к типам позволяют преобразовывать значения атрибутов Eloquent, когда вы извлекаете экземпляр модели или присваиваете их экземпляру модели.

Accessor - это геттер. Mutator - это сеттер.

Например, можно зашифровать значение при его сохранении в базу данных, а затем автоматически расшифровать это значение при доступе к нему в модели Eloquent (например шифрование паролей). Или можно преобразовать строку JSON в массив при доступе к ней через модель Eloquent.

Определение мутатора (Mutator)

Мутатор изменяет значение атрибута перед сохранением в БД.

Мутатор преобразует значение атрибута в момент их присвоения экземпляру Eloquent. Чтобы определить мутатор, необходимо назвать такой метод set{Attribute}Attribute в модели, где {Attribute} – это имя столбца, к которому нужно получить доступ. Определим мутатор для атрибута title. Этот мутатор будет автоматически вызываться, когда будет попытка присвоить значение атрибута title модели:

class Post extends Model
{
    use HasFactory;

    public function setTitleAttribute($value)
    {
            $this->attributes['title'] = strtoupper($value);
    }
}

Теперь если запустить миграцию, то все title будут в верхнем регистре.

Определение аксессора (Accessor)

Аксессор изменяет значение атрибута при получении его из БД.

Аксессор преобразует значение атрибута экземпляра Eloquent при обращении к нему. Чтобы определить метод доступа, необходимо назвать такой метод get{Attribute}Attribute модели, где {Attribute} – это имя столбца, к которому нужно получить доступ. В этом примере мы определим аксессор для атрибута title. Аксессор будет автоматически вызван Eloquent при попытке получить значение атрибута title:

class Post extends Model
{
    use HasFactory;

    public function getTitleAttribute($value)
    {
        return Str::upper($value);
    }
}

Логирование

Чтобы узнать больше о том, что происходит приложении, Laravel предлагает службы ведения журнала, которые позволяют записывать сообщения в файлы или даже в Slack, чтобы уведомить всю команду.

Ведение журнала Laravel основано на «каналах». Каждый канал представляет собой определённый способ записи информации журнала. Например, канал single записывает файлы журнала в один файл журнала, а канал slack отправляет сообщения журнала в Slack. Сообщения журнала могут быть записаны в несколько каналов в зависимости от их важности.

Под капотом Laravel использует библиотеку Monolog, которая обеспечивает поддержку множества мощных обработчиков журналов.

Конфигурирование

Все параметры конфигурации для ведения журнала приложения размещены в файле конфигурации config/logging.php. Этот файл позволяет настраивать каналы журнала приложения.

Ниже мы рассмотрим несколько распространённых вариантов.

По умолчанию Laravel будет использовать канал stack при регистрации сообщений. Канал stack используется для объединения нескольких каналов журнала в один канал.

Настройка имени канала

По умолчанию экземпляр Monolog создаётся с «именем канала», которое соответствует текущей среде, например, production или local. Чтобы изменить это значение, добавьте параметр name в конфигурацию канала:

'stack' => [
    'driver' => 'stack',
    'name' => 'channel-name',
    'channels' => ['single', 'slack'],
]

Доступные драйверы канала

Каждый канал журнала работает через «драйвер». Драйвер определяет, как и где фактически записывается сообщение журнала. Следующие драйверы канала журнала доступны в каждом приложении Laravel. Запись для большинства этих драйверов уже присутствует в файле конфигурации приложения config/logging.php.

ИмяОписание
customДрайвер, который вызывает указанную фабрику для создания канала.
dailyДрайвер Monolog на основе RotatingFileHandler с ежедневной ротацией.
errorlogДрайвер Monolog на основе ErrorLogHandler.
monologДрайвер фабрики Monolog, использующий любой поддерживаемый Monolog обработчик.
nullДрайвер, который игнорирует все сообщения.
papertrailДрайвер Monolog на основе SyslogUdpHandler.
singleКанал на основе одного файла или пути (StreamHandler)
slackДрайвер Monolog на основе SlackWebhookHandler.
stackОбертка для облегчения создания «многоканальных» каналов.
syslogДрайвер Monolog на основе SyslogHandler.

Конфигурирование каналов Single и Daily

Каналы single и daily имеют три необязательных параметра конфигурации: bubble, permission, и locking.

ИмяОписаниеПо умолчанию
bubbleДолжны ли сообщения переходить в другие каналы после обработкиtrue
lockingПопытаться заблокировать файл журнала перед записью в негоfalse
permissionПрава доступа на файл журнала0644

Конфигурирование канала Papertrail

Для канала papertrail требуются параметры конфигурации host и port. Эти значения можно получить из Papertrail.

Конфигурирование канала Slack

Для канала slack требуется параметр конфигурации url. Этот URL-адрес должен соответствовать URL-адресу входящего веб-хука, который вы настроили для своей команды Slack.

По умолчанию Slack будет получать логи только с уровнем critical и выше; однако можно настроить это в файле конфигурации config/logging.php, изменив параметр конфигурации level в массиве вашего драйвера Slack.

Построение стека журналов

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

'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['syslog', 'slack'],
    ],

    'syslog' => [
        'driver' => 'syslog',
        'level' => 'debug',
    ],

    'slack' => [
        'driver' => 'slack',
        'url' => env('LOG_SLACK_WEBHOOK_URL'),
        'username' => 'Laravel Log',
        'emoji' => ':boom:',
        'level' => 'critical',
    ]
]

Давайте разберём эту конфигурацию. Во-первых канал stack объединяет два других канала с помощью параметра channels: syslog и slack. Таким образом, при регистрации сообщений оба канала будут иметь возможность регистрировать сообщение.

Уровни журнала

Параметр конфигурации level, присутствующий в конфигурациях каналов syslog и slack в приведённом выше примере. Эта опция определяет минимальный «уровень» сообщения, которое должно быть зарегистрировано каналом. Monolog, на котором работают службы ведения журналов Laravel, предлагает все уровни журналов, определённые в спецификации RFC 5424 specification: emergency, alert, critical, error, warning, notice, info, и debug.

Итак, регистрируем сообщение, используя метод debug:

Log::debug('An informational message.');

Учитывая нашу конфигурацию, канал syslog будет записывать сообщение в системный журнал. Поскольку сообщение об ошибке не является уровнем critical или выше, то оно не будет отправлено в Slack. Однако, если мы регистрируем сообщение уровня emergency, то оно будет отправлено как в системный журнал, так и в Slack, поскольку уровень emergency выше нашего минимального порогового значения для обоих каналов:

Log::emergency('The system is down!');

На этом статья "Основы Laravel 8" заканчивается. Полную документацию можно посмотреть на официальном сайте laravel.com или русскую версию на laravel.su

Написать комментарий