Создание форума в Laravel

Добавлено: 09/06/2017 20:53 |  Обновлено: 20/02/2023 13:26 |  Добавил: nick |  Просмотры: 30413 Комментарии: 6
Вводная часть
Как вы знаете, когда-то совсем недавно первой программой каждого начинающего программиста было “Hello world!”. Сейчас, используя в своей работе фреймворки и различные библиотеки, можно уже сразу начинать с достаточно сложных проектов, таких как блог или даже простой форум. Вот созданием форума в этом материале мы и займемся. В текстовой версии (на сайте) описывается процесс создания форума в версии Laravel 5.4. В видеоверсии и в GitHub используется Laravel 10..
Для работы с данным материалом, в качестве основы, я использовал исходники с сайта laracasts.com, которые можно бесплатно скачать с GitHub. Серия уроков называется Let's Build A Forum with Laravel and TDD. Там также используется Vue.js фреймворк, но здесь я его не использую. Данный материал посвящен исключительно Laravel. Тестирование здесь также не рассматривается.

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

Главная страница форума отображает список опубликованных тем. Каждая тема состоит из раздела заголовка и раздела описания. В разделе заголовка вы можете видеть название темы и количество пользовательских сообщений в этой теме.

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

В навигационном меню слева расположены пункты: «Темы форума» и «Рубрики». В пункте справа – указано имя зарегистрированного пользователя. Все три пункта являются заголовками выпадающих меню. При нажатии на пункт пользователя можно перейти:
  • к профилю пользователя со списком созданных им тем и сообщений;
  • выйти из учетной записи пользователя.
В меню «Рубрики» можно создать новую рубрику или, выбрав одну из существующих, перейти к странице с темами этой рубрики. В меню «Темы форума» можно создать новую тему или отобразить темы разными способами. Страницы с формами создания новой рубрики и новой темы выглядят следующим образом: Алиас или псевдоним у рубрики – это слово или словосочетание, которое будет входить в адрес страницы темы из определенной рубрики.

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

Процесс регистрации/авторизации пользователя реализован стандартными средствами фреймворка. Для того чтобы добавить данный функционал в ваше приложение используйте команду: php artisan make:auth
Здесь пользователь может перейти к подробному просмотру темы, перейдя по ссылке – названию темы. Подробная страница отдельной темы выглядит следующим образом: На этой странице пользователи могут удалить свою тему или свои сообщения; могут добавлять новые сообщения в своих темах или в темах других пользователей. Также для каждого сообщения предусмотрена возможность проголосовать за сообщение (на рисунке цифра со звездочкой).

Видеоверсия (используется Laravel 10). Ссылка на плейлист

На этом описание интерфейса форума законченно. Далее рассматривается сам код приложения.

Содержание:

  1. Установка и настройка
  2. БД и маршруты
  3. Рубрики (Channels)
  4. Темы (Threads)
  5. Темы (Threads). Виды
  6. Сообщения (Replies)
  7. Личная страница пользователя
  8. Новые темы (непрочитанные)
  9. Действия пользователя. Часть 1
  10. Действия пользователя. Часть 2
  11. Действия пользователя. Часть 3
  12. Запрет отправки сообщений чаще раза в минуту

Установка и настройка

Устанавливаем фреймворк, используя composer:
composer create-project --prefer-dist laravel/laravel forum
Или с помощью их собственного установщика:
laravel new forum
В файле .env прописываем параметры доступа к БД. Далее в файле config/app.php прописываем:
'name' => 'Форум'
В дальнейшем это название будет указано в верхней навигационной панели и внутри тега title.

Далее в файле прописываем:
'locale' => 'ru'
В дальнейшем это значение будет определять атрибут lang тега html на странице.

Теперь в папке resources/views создадим папку layouts. В ней создадим два вида:
  • общий, для всего сайта – app.blade.php;
  • вид главной навигационной панели – nav.blade.php.
В файле app.blade.php будет следующее содержимое:
<!DOCTYPE html>
<html lang="{{ config('app.locale') }}">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Styles -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" >
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">

    <!-- Scripts -->
    <script>
        window.Laravel = {!! json_encode([
            'csrfToken' => csrf_token(),
        ]) !!};
    </script>

    <style>
        body { padding-bottom: 100px; }
        .level { display: flex; align-items: center; }
        .flex { flex: 1; }
    </style>
</head>
<body>
<div id="app">
    @include ('layouts.nav')
    @yield('content')
</div>

<!-- Scripts -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="{{ asset('js/app.js') }}"></script>
</body>
</html>
На страницу я добавил загрузку jquery и bootstrap. Дефолтные стили из файла css/app.css и js-код из файла js/app.js не используются, все их содержимое можно удалить.

Внутри тега div с id="app" мы включаем навигационную панель и веб контент, выводимый программно, для каждой страницы отдельно:
<div id="app">
    @include ('layouts.nav')
    @yield('content')
</div>
В файле навигационной панели nav.blade.php содержимое должно быть следующее:
<nav class="navbar navbar-inverse navbar-static-top">
    <div class="container">
        <div class="navbar-header">

            <!-- Collapsed Hamburger -->
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#app-navbar-collapse">
                <span class="sr-only">Toggle Navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>

            <!-- Branding Image -->
            <a class="navbar-brand" href="{{ url('/') }}">
                {{ config('app.name', 'Laravel') }}
            </a>
        </div>

        <div class="collapse navbar-collapse" id="app-navbar-collapse">
            <!-- Left Side Of Navbar -->
            <ul class="nav navbar-nav">
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                       aria-expanded="false">Темы форума <span class="caret"></span></a>

                    <ul class="dropdown-menu">
                        <li>
                            <a href="/threads/create">Новая тема</a>
                        </li>
                        <li role="separator" class="divider"></li>
                        <li><a href="/">Все темы</a></li>

                        @if (auth()->check())
                            <li><a href="/?by={{ auth()->user()->name }}">Мои темы</a></li>
                        @endif

                        <li><a href="/?popular=1">Популярные темы</a></li>
                        <li><a href="/?answered=1">Темы с сообщениями</a></li>
                    </ul>
                </li>

                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                       aria-expanded="false">Рубрики <span class="caret"></span></a>

                    <ul class="dropdown-menu" aria-labelledby="dropdownMenuDivider">
                    <li>
                        <a href="/channels/create">Новая рубрика</a>
                    </li>
                    <li role="separator" class="divider"></li>
                        @foreach ($channels as $channel)
                            <li><a href="/threads/{{ $channel->slug }}">{{ $channel->name }}</a></li>
                        @endforeach
                    </ul>
                </li>
            </ul>

            <!-- Right Side Of Navbar -->
            <ul class="nav navbar-nav navbar-right">
                <!-- Authentication Links -->
                @if (Auth::guest())
                    <li><a href="{{ route('login') }}">Войти</a></li>
                    <li><a href="{{ route('register') }}">Зарегистрироваться</a></li>
                @else
                    <li class="dropdown">
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button"
                           aria-expanded="false">
                            {{ Auth::user()->name }} <span class="caret"></span>
                        </a>

                        <ul class="dropdown-menu" role="menu">
                            <li>
                                <a href="{{ route('profile', Auth::user()) }}">Мой профиль</a>
                            </li>

                            <li>
                                <a href="{{ route('logout') }}"
                                   onclick="event.preventDefault();
                                                     document.getElementById('logout-form').submit();">
                                    Выйти
                                </a>

                                <form id="logout-form" action="{{ route('logout') }}" method="POST"
                                      style="display: none;">
                                    {{ csrf_field() }}
                                </form>
                            </li>
                        </ul>
                    </li>
                @endif
            </ul>
        </div>
    </div>
</nav>
Несколько слов об участке кода:
@if (auth()->check())
    <li><a href="/?by={{ auth()->user()->name }}">Мои темы</a></li>
@endif
<li><a href="/?popular=1">Популярные темы</a></li>
<li><a href="/?answered=1">Темы с сообщениями</a></li>
Здесь вы видите, что ссылки указывают на корень сайта (/), за обработку этого маршрута будет отвечать контроллер, который «вытащит» из запроса эти GET-параметры, используя метод $request->intersect() и вернет нужный набор тем из БД.

С основной разметкой и настройками мы закончили. Далее нас ждет работа с БД и маршрутами.
К содержанию

Оставьте свой комментарий

Комментарии