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

Добавлено: 09/06/2017 23:53 |  Обновлено: 19/11/2017 16:27 |  Добавил: nick |  Просмотры: 2387 Комментарии: 3
Вводная часть
Как вы знаете, когда-то совсем недавно первой программой каждого начинающего программиста было “Hello world!”. Сейчас, используя в своей работе фреймворки и различные библиотеки, можно уже сразу начинать с достаточно сложных проектов, таких как блог или даже простой форум. Вот созданием форума в этом материале мы и займемся. Пример разрабатывается в версии Laravel 5.4.
Для работы с данным материалом, в качестве основы, я использовал исходники с сайта laracasts.com, которые можно бесплатно скачать с GitHub. Серия уроков называется Let's Build A Forum with Laravel and TDD. Там также используется Vue.js фреймворк, но здесь я его не использую. Данный материал посвящен исключительно Laravel. Тестирование здесь также не рассматривается.

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

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

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

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

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

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

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

Дополнительно:

Содержание:

  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() и вернет нужный набор тем из БД.

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

Комментарии

  • 06/09/2017 15:23 Иван пишет:

    Спасибо! Очень круто обьясняете в статьях

    nick пишет:
    Спасибо за отзыв :-)

  • 06/09/2017 15:13 Иван пишет:

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

    nick пишет:
    Оригинал этого проекта называетеся Let's Build A Forum with Laravel and TDD. Его можно посмотреть на сайте laracasts.com (laracasts.com/series/lets-build-a-forum-with-laravel). Там есть ссылки на Гитхаб. Можете посмотреть там. Расположение всех файлов и у меня и там идентично.

  • 04/09/2017 13:52 ivan пишет:

    Куда ложить классы: Filters и ThreadFilters ?

    nick пишет:
    Папка app/Filters. Вы ее создаете сами.

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