laravel backend vue frontend

laravelをbackend、vueをfrontendにしたつぶやきwebアプリを作って自分の確認のために書いておきます。

まず、vueは画面表示だけ、laravelの方でつぶやきもユーザーも管理する方向で作っていきました。

laravelのAuthControllerもこんな感じ

```
<?php

namespace App\Http\Controllers;
use App\Http\Requests\UserLoginRequest;
use App\Http\Requests\UserRegisterRequest;
use App\Http\Resources\User as UserResource;
use App\User;
use Illuminate\Http\Request;

class AuthController extends Controller {
	public function register(UserRegisterRequest $request) {
		$user = User::create([
			'email' => $request->email,
			'name' => $request->name,
			'password' => bcrypt($request->password),
		]);

		if (!$token = auth()->attempt($request->only(['email', 'password']))) {
			return abort(401);
		};

		return (new UserResource($request->user()))->additional([
			'meta' => [
				'token' => $token,
			],
		]);
	}

	public function login(UserLoginRequest $request) {
		if (!$token = auth()->attempt($request->only(['email', 'password']))) {
			return response()->json([
				'errors' => [
					'email' => ['Sorry we cant find you with those details.'],
				],
			], 422);
		};

		return (new UserResource($request->user()))->additional([
			'meta' => [
				'token' => $token,
			],
		]);
	}

	public function user(Request $request) {
		return new UserResource($request->user());
	}

	public function logout() {
		auth()->logout();
	}
}
```

backend/app/Http/Controllers/PostController.phpも

```
<?php

namespace App\Http\Controllers;

use App\Http\Requests\StorePostRequest;
use App\Http\Requests\UpdatePostRequest;
use App\Http\Resources\Post as PostResource;
use App\Post;
use App\Topic;
use Illuminate\Http\Request;

class PostController extends Controller {
	public function store(StorePostRequest $request, Topic $topic) {
		$post = new Post;
		$post->body = $request->body;
		$post->user()->associate($request->user());

		$topic->posts()->save($post);
		return new PostResource($post);
	}

	public function show(Request $request, Topic $topic, Post $post) {
		return new PostResource($post);
	}

	public function update(UpdatePostRequest $request, Topic $topic, Post $post) {
		$this->authorize('update', $post);
		$post->body = $request->get('body', $post->body);
		$post->save();
		return new PostResource($post);
	}

	public function destroy(Topic $topic, Post $post) {
		$this->authorize('destroy', $post);
		$post->delete();
		return response(null, 204);
	}
}

````

backend/app/Http/Controllers/TopicsController.php

```
<?php

namespace App\Http\Controllers;

use App\Http\Requests\TopicCreateRequest;
use App\Http\Requests\UpdateTopicRequest;
use App\Http\Resources\Topic as TopicResource;
use App\Post;
// use Illuminate\Http\Request;
use App\Topic;

class TopicController extends Controller {
	public function index() {
		$topics = Topic::latestFirst()->paginate(5);
		return TopicResource::collection($topics);
	}

	public function store(TopicCreateRequest $request) {
		$topic = new Topic;
		$topic->title = $request->title;
		$topic->user()->associate($request->user());

		$post = new Post;
		$post->body = $request->body;
		$post->user()->associate($request->user());

		$topic->save();
		$topic->posts()->save($post);

		return new TopicResource($topic);
	}

	public function show(Topic $topic) {
		return new TopicResource($topic);
	}

	public function update(UpdateTopicRequest $request, Topic $topic) {
		$this->authorize('update', $topic);
		$topic->title = $request->get('title', $topic->title);
		$topic->save();
		return new TopicResource($topic);
	}

	public function destroy(Topic $topic) {
		$this->authorize('destroy', $topic);
		$topic->delete();
		return response(null, 204);
	}
}

```


vue側で送られてきたデータを登録、消去、変更するだけ。
resources/viewsには何も記述しない、vueで表示するから。
ちなみにpostはトピックに対するコメント、topicはつぶやき本体。

おまちかねvueの処理の紹介

````
frontend/pages/topics/posts/index.vue
```
<template>
	<div class="container">
		<h2>Latest Topics</h2>
    <div v-for="(topic, index) in topics" :key="index" class="bg-light mt-5 mb-5" style="padding:20px;">
      <h2><nuxt-link :to="{name: 'topics-id', params: {id: topic.id}}">{{topic.title}}</nuxt-link></h2>

      <div v-if="authenticated">
        <div v-if="user.id === topic.user.id">
          <button @click="deleteTopic(topic.id)" class="btn btn-outline-danger fa fa-trash fa-2x pull-right"></button>
          
          <nuxt-link :to="{name: 'topics-edit', params: {id: topic.id}}">
            <button class="btn btn-outline-success fa fa-edit fa-2x pull-right"></button>
          </nuxt-link>
        </div>
      </div>

      <p class="text-muted">{{topic.created_at}} by {{topic.user.name}}</p>

      <div v-for="(content, index) in topic.posts" :key="index" class="ml-5 content">
        {{content.body}}
        <p class="text-muted">{{content.created_at}} by {{content.user.name}}</p>
        <!-- add likes button -->
        <div class="btn btn-outline-primary fa fa-thumbs-up ml-5 mb-2" @click="likePost(topic.id, content)">
          <span class="badge">{{content.like_count}}</span>
        </div>
      </div>
    </div>

    <nav>
      <ul class="pagination justify-content-center">
        <li v-for="(key, value) in links" class="page-item">
          <a @click="loadMore(key)" href="#" class="page-link">{{value}}</a>
        </li>
      </ul>
    </nav>
	</div>
</template>

<script>
	export default {
		data() {
			return {
				topics: [],
        links: []
			}
		},
		async asyncData({$axios}) {
			let {data, links} = await $axios.$get('/topics')
      console.log(links)
			return {
				topics: data,
        links
			}
		},
    methods: {
       async loadMore(key) {
        let {data} =  await this.$axios.$get(key)
        return this.topics = {...this.topics, ...data}
      },
      async deleteTopic(id) {
        await this.$axios.$delete(`/topics/${id}`)
        this.$router.push('/')
      },
      async likePost(topicId, content) {
        const userFromVuex = this.$store.getters["auth/user"];
        if (userFromVuex) {
          // cant like your own post
          if (userFromVuex.id === content.user.id) {
            alert('You cant like your own post')
          }
          // if user have already liked
          if (content.users) {
            if (content.users.some(user => user.id === userFromVuex.id)) {
              alert('You have already liked this post')
            } else {
              await this.$axios.$post(`/topics/${topicId}/posts/${content.id}/likes`)
              let {data, links} = await this.$axios.$get(`/topics`)
              this.topics = data
              this.links = links
            }
          }
        } else {
          alert('Please log in')
          this.$router.push('/login')
        }
      }
    }
	}
</script>

<style scoped>
  .content {
    border-left: 10px solid white;
    padding: 0 10px 0 10px;
  }
  .btn-outline-success, .btn-outline-danger {
    border: none;
  }
</style>

```