Ikeda's Blog

Laravelでブログサイトを作る 19. 管理画面・記事編集の時に、画像をアップロードできるように(TinyMCE)

はじめに

前回にて実装したTinyMCEの機能を利用して、記事の編集中に画像をアップロードする仕組みを用意します。

サーバー側での対応

Laravelのディレクトリ構造から考えまして、画像は、storageディレクトリ(storage/app/public)に保存するべきと考えました。
しかし、このディレクトリを参照することはできません。
そこで、以下のコマンドを実行しておきます。

$ php artisan storage:link

これで、public/storageにシンボリックリンクが作成されますので、storage/***.jpgのようにして画像を表示できます。

$ ls -l public/
(省略) storage -> /home/vagrant/blog/storage/app/public

TinyMCEでアップロードできるようにする

resources/views/admin/articleEdit.blade.php
前回実装したTinyMCSの記述を修正します。

<script src="{{ asset('/js/tinymce/tinymce.min.js') }}"></script>
<script>
    tinymce.init({
        selector:'textarea',
        language: "ja", // 日本語対応(https://qiita.com/nissuk/items/e31bdfa858d6c5c018c2)

        // ▼画像アップロード対応(https://www.tiny.cloud/docs/configure/file-image-upload/)
        plugins: 'image code',
        toolbar: 'undo redo | link image | code',
        image_title: true, // イメージダイアログのタイトルフィールドを有効にする
        automatic_uploads: true, // ブロブやデータのURIで表現された画像の自動アップロードを可能にする
        images_upload_url: '{{ route('admin_article_image_upload') }}?_token={{ csrf_token() }}',
        file_picker_types: 'image',
        relative_urls : false,  // 画像やリンクのパスが相対パスに変換されるのを防ぐ
        convert_urls: false,

        /* カスタムイメージピッカー */
        file_picker_callback: function (cb, value, meta) {
            var input = document.createElement('input');
            input.setAttribute('type', 'file');
            input.setAttribute('accept', 'image/*');

            input.onchange = function () {
                var file = this.files[0];

                var reader = new FileReader();
                reader.onload = function () {
                    var id = 'blobid' + (new Date()).getTime();
                    var blobCache =  tinymce.activeEditor.editorUpload.blobCache;
                    var base64 = reader.result.split(',')[1];
                    var blobInfo = blobCache.create(id, file, base64);
                    blobCache.add(blobInfo);
                    cb(blobInfo.blobUri(), { title: file.name });
                };
                reader.readAsDataURL(file);
            };

            input.click();
        },
        content_style: 'body { font-family:Helvetica,Arial,sans-serif; font-size:14px }'
    });
</script>

アップロードされた画像を保存する

ルーティング

routes/web.php
アップロードするルーティングを追加します。

Route::group(['prefix' => 'admin', 'middleware' => 'auth', 'namespace' => 'App\\Http\\Controllers\\'], function() {
    // ...省略...

    Route::post('articleImageUpload', 'ArticleController@image')->name('admin_article_image_upload'); // 画像アップロード

    // ...省略...
});

Controller

app/Http/Controllers/ArticleController.php

アップロードされた画像を保存し、パスを返却します。

/**
 * 画像アップロード
 *
 * @param Request $request
 * @return false|string
 */
public function image(Request $request) {
    // ファイルの保存(戻り値はファイル名)
    $imgpath = request()->file('file')->store('', 'public');

    // 画像パスを返却
    return json_encode(['location' => '/storage/' . $imgpath]);
}

参考文献

https://www.tiny.cloud/docs/configure/file-image-upload/
https://qiita.com/kawa_matsu/items/50306befb7a5f879e38e
https://readouble.com/laravel/7.x/ja/structure.html