むだいありー

LaravelとContentfulでブログを作り始めた #1

はじめに

「手軽にブログ始めたいけど、ちょっとくらいはコード書いたりしたいなぁ」 そんな気持ちから作り始めたこのブログを公開するまでの作業の覚え書き。 ドメインの設定はやったことがなかったから意外とハマってしまった...。 まずは導入部分。

#1って書いたけど、続きを書くかは気分次第。

環境

ドメインはムームードメインで取得。

Contentful?

ヘッドレスCMS。記事を書いたりする管理画面だけのWordPressみたいなもの。 記事をAPIで取得して、自作したサイトに表示して使う。 ContentfulではEntrytというのが記事に当たる。 API reference:Contentful Delivery API

Contentfulの登録やContentModelの登録などはここでは割愛。

何はともあれContentを取得してみる

今回はPHPでの開発なのでここで調べたりしながら実装してみる。

composerでSDKを登録

composer require contentful/contentful

contentfulのClientをServiceProviderに登録する

SPACE_IDとACCESS_TOKENはcontentfulのSettings->API keysから確認できる。 Environment IDはSettings->Environmentsから一覧で確認できる。ここでは初めから存在するmasterを使用する。 作成したCTFDeliveryClientServiceProviderapp.phpのprovidersに登録して使えるようにしておく。 次に作成するService層のClassに依存注入して使う。

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Contentful\Delivery\Client;

/**
 * Contentfulのクライアントを登録する
 *
 * Class CTFDeliveryClientServiceProvider
 * @package App\Providers
 */
class CTFDeliveryClientServiceProvider extends ServiceProvider
{
    /**
     * @var bool
     */
    protected $defer = true;

    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(Client::class, function ($app) {
            return new Client(config('app.ctf_access_token'), config('app.ctf_space_id'), config('app.ctf_env_id'));
        });
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * @return array
     */
    public function provides()
    {
        return [
            Client::class
        ];
    }
}

contentfulからPOSTを取得するService層を作成する

APIから取得されるEntryオブジェクトを操作して内容を取得する。 $entry->get($filedName, $locale)でcontentのfiledを取得できる。 contentfulで複数言語登録をしてないなら第二引数の言語指定は無くても良い。 (そもそもQueryで指定してるしな...) setContentTypeで指定する値はcontentful上のContentModel編集画面のサイドメニューで確認できる。

namespace App\Services;

use Contentful\Delivery\Client as CTFDeliveryClient;
use Contentful\Delivery\Query as CTFQuery;

class CTFEntryService
{
    protected $ctfDeliveryClient;
    protected $locale;

    private const CONTENT_TYPE_BLOG = 'blogPost';
    private const CONTENT_TYPE_TAG = 'postTag';
    private const CONTENT_PUBLISH_DATE_FORMAT = 'Y/m/d';

    /**
     * CFTEntryService constructor.
     * @param CTFDeliveryClient $ctfDeliveryClient
     */
    public function __construct(CTFDeliveryClient $ctfDeliveryClient)
    {
        $this->ctfDeliveryClient = $ctfDeliveryClient;
        $this->locale = config('app.ctf_locale');
    }

    /**
     * ブログポストの一覧を取得
     *
     * @param int $limit
     * @return array
     */
    public function getEntries(int $limit)
    {
        $ctfQuery = new CTFQuery();
        $ctfQuery->setContentType(self::CONTENT_TYPE_BLOG)->setLocale($this->locale)->orderBy('fields.publishDate', true)->setLimit($limit);
        $entries = $this->ctfDeliveryClient->getEntries($ctfQuery);

        $posts = [];
        foreach ($entries as $entry) {
            $tagObjects = $entry->get('tags', $this->locale);
            $tags = [];
            foreach ($tagObjects as$tagObject) {
                $tags[] = [
                    'tag_name' => $tagObject->get('tagName', $this->locale),
                    'slug' => $tagObject->get('slug', $this->locale)
                ];
            }
            $posts[] = [
                'entry_id' => $entry->getId(),
                'slug' => $entry->get('slug'),
                'title' => $entry->get('title'),
                'hero_image' => $entry->get('heroImage')->getFile()->getUrl(),
                'description' => $entry->get('description'),
                'publish_date' => date(self::CONTENT_PUBLISH_DATE_FORMAT, strtotime($entry->get('publishDate', $this->locale))),
                'tags' => $tags
            ];
        }
        return $posts;
    }
}

後はHomeController等の好きなところで呼ぶだけ

.envやconfigの設定を忘れずに。

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Services\CTFEntryService;

/**
 * ホーム画面コントローラー
 *
 * Class HomeController
 * @package App\Http\Controllers
 */
class HomeController extends Controller
{
    protected $ctfEntryService;

    /**
     * HomeController constructor.
     * @param CTFEntryService $ctfEntryService
     */
    public function __construct(CTFEntryService $ctfEntryService)
    {
        parent::__construct();
        $this->ctfEntryService = $ctfEntryService;
    }

    /**
     * @param Request $request
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
     */
    public function __invoke(Request $request)
    {
        $posts = $this->ctfEntryService->getEntries(10);
        return $this->createViewResponse('home', [
            'posts' => $posts
        ]);
    }
}

次回

次回は取得したContentを良い感じに表示したかった(願望)話。