Open8

【挑戦】Zennで書いた記事をLaravel 10で作ったページに連携してみた

DaiNakaDaiNaka

はじめに

今回の作ってみたシリーズは、JSON形式のデータを取得して取り扱う勉強を兼ねてアウトプットしていきたいと思います。今回も凝ったものではなく、初心者でも簡単に参考にできるようなものを目指したいと思います。

アーカイブ

No 記事 デモサイト
1 【挑戦】Laravel 8 でLINEの様なチャットサービスを作ってみた https://chat-app.dainaka.live/
2 【挑戦】Laravel 8 で簡易的な掲示板を作ってみた https://bbs-app.dainaka.live/
3 【挑戦】Laravel 8 でEvernoteの様なメモアプリを作ってみる 😢完成に至らず
4 【挑戦】Laravel 9 でポートフォリオを作ってみた https://portfolio.dainaka.live/
5 【挑戦】Laravel 9 でとてもシンプルなブログシステムを作ってみた https://blog-app.dainaka.live/
6 【挑戦】Laravel 10 でチームで使えるタスク管理システムを作ってみた https://task-app.dainaka.live/

開発環境

  • XAMPP v3.3.0
  • composer 2.5.5
  • VS Code

利用言語

  • PHP 8.2.0
  • Laravel 10.25.2
DaiNakaDaiNaka

企画

今回は、Zennで投稿された記事を取得して表示させるシステムを作っていこうと思います。
具体的には、ユーザー名を入れて記事やスクリプトを選択して表示というボタンをクリックすると、対象となる記事を表示させるシステムを作りたいと思います。

作成の流れ

  1. ユーザー名を入力するためのトップ画面を作成
  2. 表示ボタンを押した後に記事を取得する処理を作成
  3. 取得した記事をトップ画面に表示させる処理を作成

参考記事

https://zenn.dev/catnose99/articles/cb72a73368a547756862
こちらの記事のコメント欄にあるURLから記事一覧を取得できる。

記事:https://zenn.dev/api/articles?username=dainaka&order=latest
スクラップ:https://zenn.dev/api/scraps?username=dainaka&order=latest

DaiNakaDaiNaka

プロジェクトの作成

早速、プロジェクトを作成していきます。
laravel new article-app --git --branch="main"
cd article-app

次に、GitHub上に作成しておいたリポジトリと連携させていきます。
git remote add origin https://github.com/DaiNaka1207/article-app.git

最後に、GitHub上に初期状態をプッシュしていきます。
git push -u origin main

Github

https://github.com/DaiNaka1207/article-app

DaiNakaDaiNaka

環境設定

.env
- APP_NAME=laravel
+ APP_NAME="article-app"
config/app.php
- 'timezone' => 'UTC',
+ 'timezone' => 'Asia/Tokyo',

- 'locale' => 'en',
+ 'locale' => 'ja',

- 'faker_locale' => 'en_US',
+ 'faker_locale' => 'ja_JP',
DaiNakaDaiNaka

ユーザー名を入力するためのトップ画面を作成

ここでは最初にトップ画面を表示するための処理を作成していきます。

Routerを定義

web.phpを修正してウェルカムページからトップページを表示させるように変更します。

~\routes\web.php
Route::get('/', function () {
-    return view('welcome');
+    return view('top');
});

ルートを定義したらキャッシュをクリアします。
php artisan route:cahce

Viewの作成

top.blade.phpを作成してトップページを作成していきます。

~\resources\views\top.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>{{config('app.name')}}</title>

    <!-- Tailwindcss Latest -->
    <script src="https://cdn.tailwindcss.com"></script>

</head>
<body class="flex flex-col items-center bg-sky-200">

    <!-- Username input-box -->
    <div class="w-2/5 m-10">
        <h1 class="font-medium capitalize mb-2">{{config('app.name')}}</h1>
        <form class="bg-neutral-50 p-5 rounded-lg" action="" method="get">
            @csrf
            <label for="username" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Username</label>
            <div class="flex">
                <span class="inline-flex items-center px-3 text-sm text-gray-900 bg-gray-200 border border-r-0 border-gray-300 rounded-l-md dark:bg-gray-600 dark:text-gray-400 dark:border-gray-600">
                    <svg class="w-4 h-4 text-gray-500 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
                        <path d="M10 0a10 10 0 1 0 10 10A10.011 10.011 0 0 0 10 0Zm0 5a3 3 0 1 1 0 6 3 3 0 0 1 0-6Zm0 13a8.949 8.949 0 0 1-4.951-1.488A3.987 3.987 0 0 1 9 13h2a3.987 3.987 0 0 1 3.951 3.512A8.949 8.949 0 0 1 10 18Z"/>
                    </svg>
                </span>
                <input type="text" id="username" name="username" class="mr-3 rounded-none rounded-r-lg bg-gray-50 border border-gray-300 text-gray-900 focus:ring-blue-500 focus:border-blue-500 block flex-1 min-w-0 w-full text-sm p-2.5  dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" placeholder="dainaka" required>
                <button type="submit" class="text-white bg-sky-700 hover:bg-sky-800 focus:ring-4 focus:outline-none focus:ring-sky-300 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-sky-600 dark:hover:bg-sky-700 dark:focus:ring-sky-800">表示</button>
            </div>
        </form>
    </div>

    <!-- Article -->

</body>
</html>

作成した画面の確認

作成したトップ画面を表示するため、php artisan serveを実行してブラウザでhttp://localhost:8000を確認します。

DaiNakaDaiNaka

表示ボタンを押した後に記事を取得する処理を作成

ここではトップ画面でユーザー名を入力して[表示]ボタンを押した後に、Zennから該当ユーザーの記事を取得してくる処理を作成していきます。

Controllerの作成

表示ボタンを押した後に記事を取得するためのコントローラーを作成します。
php artisan make:controller ArticleController --invokable

Routerを定義

web.phpを修正してトップページを表示させる際にコントローラーを通るように変更します。

~\routes\web.php
+ use App\Http\Controllers\ArticleController;

- Route::get('/', function () {
-     return view('top');
- });
+ Route::any('/', ArticleController::class);

ルートを定義したらキャッシュをクリアします。
php artisan route:cahce

ArticleControllerの修正

ユーザー名の指定があった場合には記事を表示させて、ユーザー名の指定がない場合にはユーザー名の入力画面だけ表示させるように変更します。

~\App\Http\Controllers\ArticleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

class ArticleController extends Controller
{
    /**
     * Handle the incoming request.
     */
    public function __invoke(Request $request)
    {
        // 入力ボックスに入力された値が存在するかを判定
        if (isset($request->username)) {

            // 入力ボックスに入力がある場合の処理
            // Zennで記事一覧を取得して$resp変数へ代入
            $resp = Http::get('https://zenn.dev/api/articles?username='.$request->username.'&order=latest');

            // 取得した記事をJson形式に変換して$resp変数に代入
            $resp = $resp->json();

            // 取得した記事の'article'オブジェクトを$articles変数に代入
            $articles = $resp['articles'];

            // articles変数をarticlesという名前でtopビューへ渡して表示
            return view('top', ['articles' => $articles]);

        } else {

            // 入力ボックスに入力がない場合の処理
            // topビューを表示
            return view('top');

        };
    }
}
DaiNakaDaiNaka

取得した記事をトップ画面に表示させる処理を作成

ここではコントローラーから受け取った記事データを表示させていきます。

topの修正

~\resources\views\top.blade.php
    <!-- Article -->
+    @if (isset($articles))
+        <div class="w-2/5 m-10">
+            <h2 class="font-medium capitalize mb-2">article</h2>
+            @foreach ($articles as $article)
+                <a class="block bg-neutral-50 p-5 rounded-lg mb-5" href={{"http://zenn.dev".$article['path']}} target="_blank" rel="noopener noreferrer">
+                    <h3 class="font-medium text-lg mb-2">{{$article['emoji']}} {{$article['title']}}</h3>
+                    <p class="text-sm">
+                        <span class="mr-5">📝{{Str::substr($article['published_at'], 0, 10)}}</span>
+                        <span class="mr-5">🖊️{{$article['body_letters_count']}}</span>
+                        <span class="mr-5">🗨️{{$article['comments_count']}}</span>
+                        <span class="mr-5">🩷{{$article['liked_count']}}</span>
+                    </p>
+                </a>
+            @endforeach
+        </div>
+    @endif

作成した画面の確認

作成したトップ画面を表示するため、php artisan serveを実行してブラウザでhttp://localhost:8000を確認します。

  • 試しにユーザー名にdainakaを入力して表示しています
  • 記事をクリックすると記事の中に飛べるようにリンクしています