Магазин на Laravel 7, часть 4. Работа с моделями, создание связывающих методов моделей

02.10.2020

Теги: LaravelMySQLPHPWeb-разработкаБазаДанныхИнтернетМагазинКаталогТоваровПрактикаФреймворкШаблонСайта

Используем модели

Мы сейчас совсем не используем модели, а все необходимые данные получаем в контроллере. Особенно некрасиво выглядит метод 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 • MySQL • PHP • Web-разработка • База данных • Интернет магазин • Каталог товаров • Практика • Фреймворк • Шаблон сайта

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.