آموزش ساخت یک برنامه مشابه توییتر با لاراول و Vue.js (قسمت دوم)

نرم افزار مشابه تویتر با لاراول و Vuejs قسمت دوم

در قسمت اول آموزش ساخت یک برنامه مشابه توییتر با لاراول و Vuejs به مقدمات ساخت برنامه پرداختیم. و تا حدودی تنظیمات مربوط به لاراول و Vuejs را به سمتی بردیم که بتوانیم یک فرم توییت ایجاد کرده و آن را به کاربر موردنظر مرتبط کنیم. از طرفی با استفاده از کامپوننت Axios داده ها را به سمت سرور ارسال و خروجی دریافت شده را در رابط کاربری نمایش دادیم.

در این بخش به ادامه آموزش می پردازیم.

7- ایجاد یک کامپوننت timeline

حال دومین کامپوننت vue مان را با نام timelineComponent.vue را در فولدر resource > asset > js >component ایجاد کرده و کدهای زیر را در آن قرار می دهیم.

// TimelineComponent.vue

<template>
    <div class="col-md-8 posts">
        <p v-if="!posts.length">No posts</p>
        <div class="media" v-for="post in posts" :key="post.id">
            <img class="mr-3" />
            <div class="media-body">
                <div class="mt-3">
                    <a href="#">{{ post.user.name }}</a>
                </div>
                <p>{{ post.body }}</p>
            </div>
        </div>
    </div>
</template>
<script>
import Event from '../event.js';

export default {
    data() {
        return {
            posts: [],
            post: {}
        }
    },
    mounted() {
        Event.$on('added_tweet', (post) => {
            this.posts.unshift(post);
        });
    }
}
</script>

حال این کامپوننت را در فایل app.js  ثبت می کنیم.

// app.js

Vue.component('timeline-component', require('./components/TimelineComponent.vue'));

هر وقت این رویداد اجرا شد، یک داده جدید به آرایه posts اضافه و برای نمایش توییت های مربوط به هر کاربر از این آرایه استفاده  می کنیم.

حال این کامپوننت را در فایل home.blade.php بکار می گیریم.

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <form-component></form-component>
        <timeline-component></timeline-component>
    </div>
</div>
@endsection

فایل را ذخیره کرده و به آدرس localhost:8000/home بروید و یک توییت اضافه کنید.

8- نمایش زمان در timeline

برای نمایش زمان، باید یک پروپرتی داخل مدل post.php ایجاد و سپس از این پروپرتی برای افزودن زمان به توییت ها استفاده می کنیم.

// Post.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Post extends Model
{

    protected $fillable = ['user_id', 'body'];

    protected $appends = ['createdDate'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function getCreatedDateAttribute()
    {
        return $this->created_at->diffForHumans();
    }

}

حال می توانیم از داخل فایل timelineComponent.vue به پروپرتی createdDate دسترسی داشته باشیم.

<div class="mt-3">
   <a href="#">
     {{ post.user.name }}
   </a> | {{ post.createdDate }}
</div>

در نهایت صفحه را رفرش کرده و یک توییت جدید اضافه کنید. با این کار در قسمت زمان عبارت یک ثانیه قبل (1 second ago) یا یک چیز شبیه این را می بینید.

9- ایجاد یک پروفایل کاربر

ما از Route Model Binding برای نمایش پروفایل کاربران استفاده و برای هر کاربر (username) یک پروفایل ایجاد می کنیم.

معمولاً از username برای اینکار استفاده می شود چون به این طریق می توانیم یک url منحصر به فرد برای پروفایل هر کاربر داشته باشیم.

در هر صورت در این مثال من از نام کاربری (username) برای تولید url منحصر به فرد استفاده می کنم.

همچنین باید یک پروپرتی منحصر به فرد داخل فایل RegistryController.php بوجود بیاوریم و به این ترتیب می توانیم یک لینک منحصر به فرد برای پروفایل کاربران ایجاد کنیم.

// RegisterController.php

protected function validator(array $data)
{
   return Validator::make($data, [
      'name' => 'required|string|max:255|unique:users',
      'email' => 'required|string|email|max:255|unique:users',
      'password' => 'required|string|min:6|confirmed',
   ]);
}

حال یک کنترلر به نام UserController تولید می کنیم. دستورات زیر را در ترمینال وارد کنید.

php artisan make:controller UserController

سپس تابع زیر را در فایل UserController.php اضافه کنید.

 <?php

// UserController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;

class UserController extends Controller
{
    public function show(User $user)
    {
        return view('user', compact('user'));
    }
}

در اینجا من از Route Model Binding استفاده کردم، اما ما می خواهیم از نام کاربری (username) روی روت استفاده کنیم. سپس توسط کلید name می توان به هر کدام از کاربران دسترسی داشت.

توجه: چنانچه مفاهیم ساخت میکروبلاگ مشابه توییتر برای شما قابل درک نیست لطفا ابتدا دوره آموزشی صفر تا صد لاراول را یاد بگیرید و سپس با این فریم ورک که جادوگری بی نظیر است راحت تر کار کنید. برای دریافت این دوره آموزشی روی لینک زیر کلیک نمایید:

برای اینکار یک کلید مسیریابی داخل فایل user.php تعریف می کنیم.

// User.php

public function getRouteKeyName()
{
   return 'name';
}

یک فایل view به نام user.blade.php داخل فولدر views ایجاد کنید.

<!-- user.blade.php -->

@extends('layouts.app')

@section('content')
<div class="container">
    {{ $user->name }}
</div>
@endsection

همچنین باید یک روت داخل فایل web.php ایجاد کنید.

// web.php

<?php

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

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');
Route::post('tweet/save', 'PostController@store');

Route::get('users/{user}', 'UserController@show')->name('user.show');

من یک کاربر به نام krunal را ثبت نام کردم و برای دسترسی به پروفایل این کاربر باید به آدرس http://localhost:8000/users/krunal برویم.

با ورود به این آدرس می توانید پروفایل این کاربر را ببینید.

10- نمایش URL داخل کامپوننت timeline

معمولا هنگامی که ما از داده ای که از داده دیگر در همان جدول ایجاد شده، نیاز داشته باشیم، نباید آن داده را دوباره ذخیره کنیم بلکه باید هنگام بازیابی داده ها، رکورد داده های مرتبط را به هم الحاق (join) کنیم.

همان طور که می بینید آدرس پروفایل مبتنی بر username است، پس می توانیم یک پروپرتی جدید را به url متصل کنیم و این آدرس را به مدل user.php الحاق کنیم.

حال یک accessor برای profilelink داخل مدل user.php ایجاد می کنیم.

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    protected $fillable = [
        'name', 'email', 'password',
    ];

    protected $hidden = [
        'password', 'remember_token',
    ];

    protected $appends = ['profileLink'];

    public function posts()
    {
        return $this->hasMany(Post::class);
    }

    public function getRouteKeyName()
    {
        return 'name';
    }

    public function getProfileLinkAttribute()
    {
        return route('user.show', $this);
    }

}

حال ما این url را داخل فایل timelineComponent.vue نمایش می دهیم.

// TimelineComponent.vue

<template>
    <div class="col-md-8 posts">
        <p v-if="!posts.length">No posts</p>
        <div class="media" v-for="post in posts" :key="post.id">
            <img class="mr-3" />
            <div class="media-body">
                <div class="mt-3">
                    <a :href="post.user.profileLink">{{ post.user.name }}</a> | {{ post.createdDate }}
                </div>
                <p>{{ post.body }}</p>
            </div>
        </div>
    </div>
</template>
<script>
import Event from '../event.js';

export default {
    data() {
        return {
            posts: [],
            post: {}
        }
    },
    mounted() {
        Event.$on('added_tweet', (post) => {
            this.posts.unshift(post);
        });
    }
}
</script>

11- نمایش لینک های follow و unfollow

یک فایل migration برای جدول followers ایجاد می کنیم. برای اینکار دستورات زیر را در ترمینال اجرا کنید.

php artisan make:model Follower -m

حال کدهای زیر را در فایل create_followes_table.php قرار دهید.

// create_users_table

public function up()
{
        Schema::create('followers', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned();
            $table->integer('follower_id')->unsigned();
            $table->nullableTimestamps();

            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
            $table->foreign('follower_id')->references('id')->on('users')->onDelete('cascade');
            
        });
}

جدول را migrate کنید.

php artisan migrate

حال باید یک ارتباط با مدل user ایجاد کنیم.

// User.php

public function following()
{
   return $this->belongsToMany(User::class, followers, user_id, follower_id);
}

در قدم بعد باید چند شرط به شرح زیر را به آن اضافه کنیم:

  1. یک کاربر نمی تواند خودش را follow کند.
  2. فقط اگر کاربری کاربر دیگر را follow نکرده باشد می تواند آن را follow کند.
  3. اگر کاربری کاربر دیگر را follow کند می تواند آن را unfollow کند.

هر شرط را داخل یک تابع اختصاصی در فایل user.php تعریف می کنیم.

من تمام این سه تابع را داخل مدل user.php ایجاد می کنیم.

  1. تابع isNot
  2. تابع isFollowing
  3. تابع canFollow
<?php

// User.php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    protected $fillable = [
        'name', 'email', 'password',
    ];

    protected $hidden = [
        'password', 'remember_token',
    ];

    protected $appends = ['profileLink'];

    public function posts()
    {
        return $this->hasMany(Post::class);
    }

    public function getRouteKeyName()
    {
        return 'name';
    }

    public function getProfileLinkAttribute()
    {
        return route('user.show', $this);
    }

    public function following()
    {
        return $this->belongsToMany(User::class, 'followers', 'user_id', 'follower_id');
    }

    public function isNot($user)
    {
        return $this->id !== $user->id;
    }

    public function isFollowing($user)
    {
        return (bool) $this->following->where('id', $user->id)->count();
    }

    public function canFollow($user)
    {
        if(!$this->isNot($user)) {
            return false;
        }
        return !$this->isFollowing($user);
    }

}

تمام این شرط ها را در تابع مخصوص خودش نوشتیم. حال فایل user.blade.php را باز کرده و لینک های follow و unfollow را پیاده سازی می کنیم.

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <h3>{{ $user->name }}</h3>
            @if(auth()->user()->isNot($user))
                @if(auth()->user()->isFollowing($user))
                    <a href="#" class="btn btn-danger">No Follow</a>
                @else
                    <a href="#" class="btn btn-success">Follow</a>
                @endif
            @endif
        </div>
    </div>
</div>
@endsection

خب حال اگر شما به پروفایل تان مراجعه کنید لینک های follow و unfollow را نمی بینید. در صورتی که با نام کاربری دیگر به سایت وارد (login) شوید می توانید لینک های follow و unfollow را مشاهده کنید.

12- دنبال کردن یک کاربر

روت users/{user}/follow را در فایل web.php تعریف کنید.

<?php

// web.php

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

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');
Route::post('tweet/save', 'PostController@store');

Route::get('users/{user}', 'UserController@show')->name('user.show');

Route::get('users/{user}/follow', 'UserController@follow')->name('user.follow');

حال می توانیم متد follow() را در فایل userController.php بنویسیم.

// UserController.php

public function follow(Request $request, User $user)
{
    if($request->user()->canFollow($user)) {
        $request->user()->following()->attach($user);
    }
    return redirect()->back();
}

همچنین باید فایل user.blade.php را بروزرسانی کنیم.

@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-12">
            <h3>{{ $user->name }}</h3>
            @if(auth()->user()->isNot($user))
                @if(auth()->user()->isFollowing($user))
                    <a href="#" class="btn btn-danger">No Follow</a>
                @else
                    <a href="{{ route('user.follow', $user) }}" class="btn btn-success">Follow</a>
                @endif
            @endif
        </div>
    </div>
</div>
@endsection

حال وقتی که با نام کاربری دیگری وارد سایت شوید و آدرس پروفایل خودتان را وارد کنید، می توانید آن را follow کنید.

وقتی که روی لینک follow کلیک کنید می بینید که لینک unfollow ظاهر می شود و می توانید آن را unfollow کنید.

همچنین می بینید که جدول followers یک ورودی دارد.

ایجاد جدول برای کاربران follow شده در لاراول و Vuejs

13- unfollow کردن یک کاربر

ما می توانیم یک کاربری را که هم اکنون دنبال می کنیم را unfollow کنیم. برای اینکار تابع زیر را در فایل user.php تعریف کنید.

// User.php

public function canUnFollow($user)
{
    return $this->isFollowing($user);
}

همچنین یک روت برای unfollow کردن داخل فایل web.php تعریف می کنیم.

// web.php

Route::get('users/{user}/unfollow', 'UserController@unfollow')->name('user.unfollow');

حال تابع unfollow() را داخل فایل userController.php می نویسیم.

// UserController.php

public function unFollow(Request $request, User $user)
{
   if($request->user()->canUnFollow($user)) {
       $request->user()->following()->detach($user);
    }
       return redirect()->back();
}

همچنین باید فایل user.blade.php  را بروزرسانی کنیم.

@if(auth()->user()->isNot($user))
      @if(auth()->user()->isFollowing($user))
           <a href="{{ route('user.unfollow', $user) }}" class="btn btn-danger">No Follow</a>
      @else
           <a href="{{ route('user.follow', $user) }}" class="btn btn-success">Follow</a>
      @endif
@endif

به این ترتیب توانستیم قابلیت follow و unfollow را پیاده کنیم.

14- بازیابی توییت های کاربرانی که آنها را دنبال می کنیم

در این مرحله باید توییت های تمام کاربرانی که آنها را دنبال میکنیم را بازیابی کنیم، یعنی وقتی که ما کاربری را دنبال میکنیم باید بتوانیم توییت هایشان را ببینیم.

برای این کار ما متد index() را داخل فایل postController.php تعریف میکنیم

<?php

// PostController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Post;

class PostController extends Controller
{

    public function index(Request $request, Post $post)
    {
        $posts = $post->whereIn('user_id', $request->user()->following()
                        ->pluck('users.id')
                        ->push($request->user()->id))
                        ->with('user')
                        ->orderBy('created_at', 'desc')
                        ->take($request->get('limit', 10))
                        ->get();
          
        return response()->json($posts);
    }

    public function store(Request $request, Post $post)
    {
        $newPost = $request->user()->posts()->create([
            'body' => $request->get('body')
        ]);
   
        return response()->json($post->with('user')->find($newPost->id));
    }
}

ما تمام پست های کاربرانی که آنها را دنبال میکنیم را بازیابی کردیم. تعداد کاربران ممکن است بیش از یک مورد باشد.

در کد بالا من گفتم که کاربر جاری که وارد سیستم شده است می تواند هم پست های خودش و هم پست های کاربرانی که آنها را دنبال می کند را ببیند.

در مرحله بعد باید همه این پست ها را نمایش دهیم.

یک روت برای این تابع index() تعریف میکنیم.

// web.php

Route::get('posts', 'PostController@index')->name('posts.index');

سپس باید یک درخواست از سمت کاربر به سرور را با کتابخانه Axios ارسال کنیم که این کار را در فایل timelineComponent.vue انجام می دهیم.

// TimelineComponent.vue

<template>
    <div class="col-md-8 posts">
        <p v-if="!posts.length">No posts</p>
        <div class="media" v-for="post in posts" :key="post.id">
            <img class="mr-3" />
            <div class="media-body">
                <div class="mt-3">
                    <a :href="post.user.profileLink">{{ post.user.name }}</a> | {{ post.createdDate }}
                </div>
                <p>{{ post.body }}</p>
            </div>
        </div>
    </div>
</template>
<script>
import Event from '../event.js';

export default {
    data() {
        return {
            posts: [],
            post: {}
        }
    },
    mounted() {
        axios.get('/posts').then((resp => {
            this.posts = resp.data;
        }));
        Event.$on('added_tweet', (post) => {
            this.posts.unshift(post);
        });
    }
}
</script>

حالا می توانید هم پست های کاربرانی که آنها را دنبال می کنید و هم پست های خودتان را مشاهده کنید.

مشاهده توییت کاربران در لاراول و Vuejs

نتیجه گیری

به این ترتیب آموزش ما به اتمام رسید. در این آموزش لاراول و Vuejs از مفاهیم زیادی استفاده کردیم. امیدوارم بتوانید از این آموزش در پروژه های خودتان بهره ببرید. این دقیقاً مانند برنامه توییتر نیست، اما سعی کردم مفاهیم زیادی از قبیل نحوه کار با رویدادها در vue ، ارتباط بین مدل ها در لاراول و  کوئری های پیچیده را به شما آموزش بدهم. تمام کدهای این پروژه را در سایت گیت هاب آپلود کردم که در صورت نیاز می توانید آن را دریافت کنید.

برای استفاده از کدهایی که در گیت هاب قرار دادم مراحل زیر را دنبال کنید:

  1. از ریپازیتوری clone بگیرید (دانلود کنید) به داخل فولدر پروژه بروید.
  2. ترمینال را باز کنید و به فولدر پروژه وارد شده و دستور composer install را تایپ کنید.
  3. وابستگی های npm را نصب کنید: npm install
  4. دستور زیر را اجرا کنید: npm run watch
  5. یک دیتابیس ایجاد کنید و اطلاعات آن را در فایل .env وارد کنید.
  6. دیتابیس را migrate کنید
  7. به آدرس http://localhost:8000/register رفته و دو کاربر را ثبت کنید.
  8. تعدادی توییت را با کاربر وارد شده به سیستم ایجاد کنید.
  9. از سیستم log out کنید و با کاربر دوم وارد سایت شوید (login)
  10. به پروفایل کاربر اولی رفته و آن را follow کنید.
  11. به صفحه home بروید. همان طور که می بینید پست های کاربرانی که آنها را دنبال کردید در این صفحه نمایش داده می شوند.
  12. حال با اکانت کاربر دومی چند توییت ایجاد کنید، به این ترتیب توییت های جدید را هم در صفحه  home کاربر اول (مرحله 11) نمایش داده می شوند
نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.