Магазин на Laravel 7, часть 4. Работа с моделями, создание связывающих методов моделей
02.10.2020
Теги: Laravel • MySQL • PHP • Web-разработка • БазаДанных • ИнтернетМагазин • КаталогТоваров • Практика • Фреймворк • ШаблонСайта
Используем модели
Мы сейчас совсем не используем модели, а все необходимые данные получаем в контроллере. Особенно некрасиво выглядит метод product()
контроллера, где у нас большой и сложный запрос к базе данных. Давайте упростим методы контроллера, и будем использовать модели по их прямому назначению — для получения данных.
namespace App; use Illuminate\Database\Eloquent\Model; class Category extends Model { /** * Возвращает список товаров выбранной категории */ public function getProducts() { return Product::where('category_id', $this->id)->get(); } }
namespace App; use Illuminate\Database\Eloquent\Model; class Brand extends Model { /** * Возвращает список товаров выбранного бренда */ public function getProducts() { return Product::where('brand_id', $this->id)->get(); } }
namespace App; use Illuminate\Database\Eloquent\Model; class Product extends Model { /** * Возвращает категорию выбранного товара */ public function getCategory() { return Category::find($this->category_id); } /** * Возвращает бренд выбранного товара */ public function getBrand() { return Brand::find($this->brand_id); } }
Теперь наш контроллер выглядит уже лучше:
namespace App\Http\Controllers; use App\Brand; use App\Category; use App\Product; use Illuminate\Http\Request; class CatalogController extends Controller { public function index() { $roots = Category::where('parent_id', 0)->get(); return view('catalog.index', compact('roots', 'products')); } public function category($slug) { $category = Category::where('slug', $slug)->firstOrFail(); // получаем товары категории от модели $products = $category->getProducts(); return view('catalog.category', compact('category', 'products')); } public function brand($slug) { $brand = Brand::where('slug', $slug)->firstOrFail(); // получаем товары бренда от модели $products = $brand->getProducts(); return view('catalog.brand', compact('brand', 'products')); } public function product($slug) { $product = Product::where('slug', $slug)->firstOrFail(); // получаем от модели категорию и бренд товара $category = $product->getCategory(); $brand = $product->getBrand(); return view('catalog.product', compact('product', 'category', 'brand')); } }
Связи моделей
Но мы пойдем дальше и будем использовать связи моделей:
namespace App; use Illuminate\Database\Eloquent\Model; class Category extends Model { /** * Связь «один ко многим» таблицы `categories` с таблицей `products` */ public function products() { return $this->hasMany(Product::class); } }
namespace App; use Illuminate\Database\Eloquent\Model; class Brand extends Model { /** * Связь «один ко многим» таблицы `brands` с таблицей `products` * * @return \Illuminate\Database\Eloquent\Relations\HasMany */ public function products() { return $this->hasMany(Product::class); } }
namespace App; use Illuminate\Database\Eloquent\Model; class Product extends Model { /** * Связь «товар принадлежит» таблицы `products` с таблицей `categories` */ public function category() { return $this->belongsTo(Category::class); } /** * Связь «товар принадлежит» таблицы `products` с таблицей `brands` */ public function brand() { return $this->belongsTo(Brand::class); } }
Теперь наш контроллер выглядит еще лучше:
namespace App\Http\Controllers; use App\Brand; use App\Category; use App\Product; use Illuminate\Http\Request; class CatalogController extends Controller { public function index() { $roots = Category::where('parent_id', 0)->get(); return view('catalog.index', compact('roots')); } public function category($slug) { $category = Category::where('slug', $slug)->firstOrFail(); return view('catalog.category', compact('category')); } public function brand($slug) { $brand = Brand::where('slug', $slug)->firstOrFail(); return view('catalog.brand', compact('brand')); } public function product($slug) { $product = Product::where('slug', $slug)->firstOrFail(); return view('catalog.product', compact('product')); } }
В шаблоне страницы товара получить доступ к объекту категории товара можно через свойство category
. Аналогично, получить доступ к объекту бренда товара можно через свойство brand
.
@extends('layout.site') @section('content') <div class="row"> <div class="col-12"> <div class="card"> <div class="card-header"> <h1>{{ $product->name }}</h1> </div> <div class="card-body"> <div class="row"> <div class="col-md-6"> <img src="https://via.placeholder.com/400x400" alt="" class="img-fluid"> </div> <div class="col-md-6"> <p>Цена: {{ number_format($product->price, 2, '.', '') }}</p> </div> </div> <div class="row"> <div class="col-12"> <p class="mt-4 mb-0">{{ $product->content }}</p> </div> </div> </div> <div class="card-footer"> <div class="row"> <div class="col-md-6"> @isset($product->category) Категория: <a href="{{ route('catalog.category', ['slug' => $product->category->slug]) }}"> {{ $product->category->name }} </a> @endisset </div> <div class="col-md-6 text-right"> @isset($product->brand) Бренд: <a href="{{ route('catalog.brand', ['slug' => $product->brand->slug]) }}"> {{ $product->brand->name }} </a> @endisset </div> </div> </div> </div> </div> </div> @endsection
Изменим шаблоны списка товаров категории и списка товаров бренда:
@extends('layout.site') @section('content') <h1>{{ $category->name }}</h1> <p>{{ $category->content }}</p> <div class="row"> @foreach ($category->products as $product) @include('part.product') @endforeach </div> @endsection
@extends('layout.site') @section('content') <h1>{{ $brand->name }}</h1> <p>{{ $brand->content }}</p> <div class="row"> @foreach ($brand->products as $product) @include('part.product') @endforeach </div> @endsection
Страница 404
Разместим картинку 404.jpg
в директории public/img
, где она будет доступна из веб. Создадим директорию resources/views/errors
и внутри нее — шаблон 404.blade.php
.
@extends('layout.site', ['title' => 'Страница не найдена']) @section('content') <div class="row"> <div class="col-12"> <div class="card mt-4 mb-4"> <div class="card-header"> <h1>Страница не найдена</h1> </div> <div class="card-body"> <img src="{{ asset('img/404.jpg') }}" alt="" class="img-fluid"> </div> <div class="card-footer"> <p>Запрошенная страница не найдена.</p> </div> </div> </div> </div> @endsection
- Магазин на Laravel 7, часть 24. Фильтр товаров категории по цене, новинкам и лидерам продаж
- Магазин на Laravel 7, часть 23. Главная страница сайта, новинки, лидеры продаж и распродажа
- Магазин на Laravel 7, часть 21. Добавляем профили и используем их при оформлении заказа
- Магазин на Laravel 7, часть 20. Показ отдельной страницы и верхнее меню всех страниц
- Магазин на Laravel 7, часть 18. Панель управления, пользователи и CRUD страниц сайта
- Магазин на Laravel 7, часть 17. Панель управления, работа с заказами, изменение статуса
- Магазин на Laravel 7, часть 16. Панель управления, CRUD-операции для товаров каталога
Поиск: Laravel • MySQL • PHP • Web-разработка • База данных • Интернет магазин • Каталог товаров • Практика • Фреймворк • Шаблон сайта