20190707のlaravelに関する記事は5件です。

【Laravel】Vue.jsでFile APIを使って画像プレビューを行なう方法

画像プレビューを実装

今回のゴールはこちら。

プレビュー.mov.gif

File API

File APIについて
ローカルで選択した File情報を取得できます。

ただし、File APIを使わなくても以下の項目は普通に取得できます。
更新日時
ファイル名
データサイズ(バイト数)
MIMEタイプ(ファイルの種類)

コード

sample.php
    <div id="imgview">
        <img-view></img-view>
    </div>

使用するVueをコンポーネントとして登録。

app.js
Vue.component('img-upload', require('./components/ImgView.vue').default);
ImgView.vue
<template>
  <label for="file-sample">
     <div class="drop">
        <input class="input" id="file-sample" type="file" name="user_img" @change="onFileChange">
        <i aria-hidden="true" class="fas fa-plus fa-7x"></i>
        <img class="img" id="file-preview" v-show="uploadedImage" :src="uploadedImage">
     </div>
  </label>
</template>

<script>
export default {
    data() {
         return {
             uploadedImage: "",
         };
    },
    methods: {
        onFileChange(e) {
            let files = e.target.files;
            this.createImage(files[0]); //File情報格納
        },
        //アップロードした画像を表示
        createImage(file) {
            let reader = new FileReader(); //File API生成
            reader.onload = (e) => {
                this.uploadedImage = e.target.result;
            };

            reader.readAsDataURL(file);
        },
    },
 }
</script>

inputタグに@changeを、imgタグにv-showを使います。
v-showに設定しているuploadedImageはimgタグのsrcにも設定されていて、uploadedImageにFile情報が入ると同時にsrcにもソースとしてFile情報が格納され表示されると言う仕組みです。

なので最初の時点では何も入っておらず、v-showはfalseになるのでdisplay: none;が適用されています。

methods

onFileChangeでは選択されたFile情報を変数に格納。

files[0]を引数にcreateImage()メソッドを呼び出します。

ここでは、FileReaderときうオブジェクトを生成します。
onloadは正常にファイルを読み込んだときに発生するイベントです。
この中でuploadedImageに event.target.resultのデータを格納。

event.target.resultには画像データをテキストデータにしたものが入っています。
※これをData URIをスキーム化させると言うみたいです。

最後にreadAsDataURL()で画像の読み込みを実行します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでAPIを作成して、ReactのJSXにそのデータを表示したい

開発環境

  • laravel 5.8
  • docker

dockerは、LaradockでLaravel+Docker環境構築(mac)の方法で環境構築しました。

概要

LaravelでReactを使用できる方法から、Apiを作成してReactのJSXで表示したい

Reactへ切り替え

laravelのあるディレクトリへ移動

$ cd project

vue.jsからreactへ切り替え

$ php artisan preset react
React scaffolding installed successfully.
Please run "npm install && npm run dev" to compile your fresh scaffolding.

npmをインストール

$ npm install 

JSファイルの保存を監視とビルドのため実行(control+cで終了)

$ npm run watch

reactに切り替わっているか確認
resources/js/componentsがExample.vueからExample.jsになっていれば成功

Example.js編集

Example ComponentをReactに変更

Example.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

export default class Example extends Component {
    render() {
        return (
            <div className="container">
                <div className="row justify-content-center">
                    <div className="col-md-8">
                        <div className="card">
                            <div className="card-header">React</div>

                            <div className="card-body">I'm an example component!</div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

if (document.getElementById('example')) {
    ReactDOM.render(<Example />, document.getElementById('example'));
}

次にwelcome.blade.phpのbodyタグを下記のように修正する。

id=exampleの要素から、Exampleがクラスが呼び出される。

welcome.blade.php
<body>
        <div id="example"></div>
        <script src="{{mix('js/app.js')}}" ></script>
</body>

localhostでアクセスすると修正した内容が反映されています。

LaravelをApiとして使う準備

非同期で処理できるようにしたので、laravelをapi化します。今回はapp/Http/Controllers/api配下にPostControllerを作成します。

$ php artisan make:controller api/PostController

apiのルーティングは、route/api.phpがあるので、以下のように記述します。

route/api.php
Route::group(['middleware' => ['api']], function() {
    Route::resource('post' , 'api\PostController');
});

modelとmigration作成

$ php artisan make:model Post -m

中身はcontentカラムを追加します

public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->bigIncrements('id');
            // name,contentカラム追加
            $table->string('name');
            $table->text('content');
            $table->timestamps();
        });
    }

シーダーの作成

$ php artisan make:seeder PostsTableSeeder
public function run()
    {
        \DB::table('posts')->insert([
            [
                'name' => '名前1',
                'content' => '内容1'
            ],
            [
                'name' => '名前2',
                'content' => '内容2'
            ],
            [
                'name' => '名前3',
                'content' => '内容3'
            ],
        ]);
    }

database/seeds/DatabaseSeederにPostsTableSeederを追記して

public function run()
{
  $this->call(PostsTableSeeder::class);
}

マイグレーションとシーダーを実行

$ php artisan migrate --seed

PostControllerのindexで作成したPostモデルを、jsonで返す

PostController.php
public function index() 
{
    $posts = Post::all();   
    return response()->json($posts, 200);
}

本来なら、postman等のツールで確認しますが、今回はブラウザでhttp://localhost/api/posts
を直接叩いて、jsonで帰ってきたら成功

react側でapiの利用

先ほど作成したPostモデルのデータをaxiosを使ってreact側で受け取ります。

axiosは、HTTPリクエストを送信するメソッドです。
今回はGETリクエストを送信します。

Example.jsを下記のように修正します。

Example.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';

export default class Example extends Component {

    constructor() {
        super();

        this.state = {
            posts: []
        };
    }
    componentDidMount() {
        axios
            .get('/api/posts')
            .then(response => {
                this.setState({posts: response.data});
            })
            .catch(() => {
                console.log('通信に失敗しました');
            });
    }

    renderPosts() {
        return this.state.posts.map(post => {
            return (
                <li key={post.key}>
                    {post.name}: {post.content}
                </li>
            );
        });
    }

    render() {
        return (
            <div className="container">
                <ul>
                    {this.renderPosts()}
                </ul>
            </div>
        );
    }
}

if (document.getElementById('example')) {
    ReactDOM.render(<Example />, document.getElementById('example'));
}

まず初めconstructorのstateに、取得するpostsを格納する為に、空配列を用意します。

constructor() {
     super();

     this.state = {
         posts: []
     };
 }

次に、コンポーネントがマウントされた直後に呼ばれるcomponentDidMountにaxiosを記述して、stateの中にapiから取得したpostsを格納します。例外処理は、コンソールでエラーを返すようにします。

componentDidMount() {
    axios
        .get('/api/posts')
        .then(response => {
            this.setState({posts: response.data});
        })
        .catch(() => {
            console.log('通信に失敗しました');
        });
}

最後に、renderPostsメソッドで配列をループして、JSXでこのメソッドを呼び出します。

renderPosts() {
    return this.state.posts.map(post => {
        return (
            <li key={post.key}>
                {post.name}: {post.content}
            </li>
        );
    });
}

render() {
    return (
        <div className="container">
            <ul>
                {this.renderPosts()}
            </ul>
        </div>
    );
}

これで、laravelでreactのセットアップから、apiからデータを取得して、jsxで表示するところまでできました。

スクリーンショット 2019-07-07 19.06.21.png

以上です。
次回は、Reduxの導入でもしたいと思っています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでAPIを作成して、Reactで取得したい

開発環境

  • laravel 5.8
  • docker

dockerは、LaradockでLaravel+Docker環境構築(mac)の方法で環境構築しました。

概要

LaravelでReactを使用できる方法から、Apiを作成してReactのJSXで表示したい

Reactへ切り替え

laravelのあるディレクトリへ移動

$ cd project

vue.jsからreactへ切り替え

$ php artisan preset react
React scaffolding installed successfully.
Please run "npm install && npm run dev" to compile your fresh scaffolding.

npmをインストール

$ npm install 

JSファイルの保存を監視とビルドのため実行(control+cで終了)

$ npm run watch

reactに切り替わっているか確認
resources/js/componentsがExample.vueからExample.jsになっていれば成功

Example.js編集

Example ComponentをReactに変更

Example.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';

export default class Example extends Component {
    render() {
        return (
            <div className="container">
                <div className="row justify-content-center">
                    <div className="col-md-8">
                        <div className="card">
                            <div className="card-header">React</div>

                            <div className="card-body">I'm an example component!</div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

if (document.getElementById('example')) {
    ReactDOM.render(<Example />, document.getElementById('example'));
}

次にwelcome.blade.phpのbodyタグを下記のように修正する。

id=exampleの要素から、Exampleがクラスが呼び出される。

welcome.blade.php
<body>
        <div id="example"></div>
        <script src="{{mix('js/app.js')}}" ></script>
</body>

localhostでアクセスすると修正した内容が反映されています。

LaravelをApiとして使う準備

次に、laravelをapi化します。今回はapp/Http/Controllers/api配下にPostControllerを作成します。

$ php artisan make:controller api/PostController

apiのルーティングは、route/api.phpがあるので、以下のように記述します。

route/api.php
Route::group(['middleware' => ['api']], function() {
    Route::resource('post' , 'api\PostController');
});

modelとmigration作成

$ php artisan make:model Post -m

中身はname、contentカラムを追加します

public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->bigIncrements('id');
            // name,contentカラム追加
            $table->string('name');
            $table->text('content');
            $table->timestamps();
        });
    }

シーダーの作成

$ php artisan make:seeder PostsTableSeeder
public function run()
    {
        \DB::table('posts')->insert([
            [
                'name' => '名前1',
                'content' => '内容1'
            ],
            [
                'name' => '名前2',
                'content' => '内容2'
            ],
            [
                'name' => '名前3',
                'content' => '内容3'
            ],
        ]);
    }

database/seeds/DatabaseSeederにPostsTableSeederを追記して

public function run()
{
  $this->call(PostsTableSeeder::class);
}

マイグレーションとシーダーを実行

$ php artisan migrate --seed

PostControllerのindexで作成したPostモデルを、jsonで返す

PostController.php
public function index() 
{
    $posts = Post::all();   
    return response()->json($posts, 200);
}

本来なら、postman等のツールで確認しますが、今回はブラウザでhttp://localhost/api/posts
を直接叩いて、jsonで帰ってきたら成功

react側でapiの利用

先ほど作成したPostモデルのデータをaxiosを使ってreact側で受け取ります。

axiosは、HTTPリクエストを送信するメソッドです。
今回はGETリクエストを送信します。

Example.jsを下記のように修正します。

Example.js
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';

export default class Example extends Component {

    constructor() {
        super();

        this.state = {
            posts: []
        };
    }
    componentDidMount() {
        axios
            .get('/api/posts')
            .then(response => {
                this.setState({posts: response.data});
            })
            .catch(() => {
                console.log('通信に失敗しました');
            });
    }

    renderPosts() {
        return this.state.posts.map(post => {
            return (
                <li key={post.key}>
                    {post.name}: {post.content}
                </li>
            );
        });
    }

    render() {
        return (
            <div className="container">
                <ul>
                    {this.renderPosts()}
                </ul>
            </div>
        );
    }
}

if (document.getElementById('example')) {
    ReactDOM.render(<Example />, document.getElementById('example'));
}

まず初めconstructorのstateに、取得するpostsを格納する為に、空配列を用意します。

constructor() {
     super();

     this.state = {
         posts: []
     };
 }

次に、コンポーネントがマウントされた直後に呼ばれるcomponentDidMountにaxiosを記述して、stateの中にapiから取得したpostsを格納します。例外処理は、コンソールでエラーを返すようにします。

componentDidMount() {
    axios
        .get('/api/posts')
        .then(response => {
            this.setState({posts: response.data});
        })
        .catch(() => {
            console.log('通信に失敗しました');
        });
}

最後に、renderPostsメソッドで配列をループして、JSXでこのメソッドを呼び出します。

renderPosts() {
    return this.state.posts.map(post => {
        return (
            <li key={post.key}>
                {post.name}: {post.content}
            </li>
        );
    });
}

render() {
    return (
        <div className="container">
            <ul>
                {this.renderPosts()}
            </ul>
        </div>
    );
}

これで、laravelでreactのセットアップから、apiからデータを取得して、jsxで表示するところまでできました。

スクリーンショット 2019-07-07 19.06.21.png

以上です。
次回は、Reduxの導入でもしたいと思っています。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelでコントローラーからviewへの変数の受け渡しについてメモ

Laravelの勉強がてらメモ。

viewヘルパ関数

Laravelでコントローラーからviewへ変数を渡す方法としては、

$data = array(
    "name" => "Tanaka",
    "age" => 30,
);
return view('user', $data);

viewヘルパ関数を使用。

第1引数は、resources/viewsディレクトリ配下のファイル名。

ちなみにresources/viewsディレクトリ配下にディレクトリを作成し、その中にファイルを作成している場合は、ドットでつなぐ。

resources/views/admin/user.phpの場合
$data = array(
    "name" => "Tanaka",
    "age" => 30,
);
return view('admin.user', $data);

第2引数に配列を設定することで、ビューに変数を渡すことが可能。

withメソッドを使用

他のやり方としては、withメソッドで変数を渡すこともできる。

return view('admin.user')->with('name', 'Tanaka');

compact関数を使用

compact関数を使用すると、もっと楽に変数をビューに渡せる。

$name = "Tanaka";
$age = 30;
return view('user', compact("name", "age"));

compact関数ってLaravel特有の関数かと思いこんでましたけど、
普通にPHPの関数でした。

https://php.net/manual/ja/function.compact.php

compact関数の結果を試しに出力。

$name = "Tanaka";
$age = 30;
var_dump(compact("name", "age"));
出力結果
array(2) {
  ["name"]=>
  string(6) "Tanaka"
  ["age"]=>
  int(30)
}

やってることは、

$data = array(
    "name" => "Tanaka",
    "age" => 30,
);
return view('user', $data);

と同じですね。納得。

誰かスマートな書き方をした人のコードが広まったんだろうなぁ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

作成したLaravelコンテナを軽量化する

どうも、若松です。

前回はDockerでLaravelを起動するまでをまとめました。
https://qiita.com/t_wkm2/items/9b2011af9569627fee40

しかしながら、現在のコンテナイメージはお世辞にも軽量とは言えません。
コンテナイメージサイズはコンテナ起動時間に直結するため、できるだけ軽量化していきたいと思います。

Dockerfile

FROM amazonlinux:2 as vender

# PHPインストール
RUN amazon-linux-extras install -y php7.3
RUN yum install -y php-pecl-zip php-mbstring php-dom

# Composerインストール
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
RUN php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
RUN php composer-setup.php
RUN php -r "unlink('composer-setup.php');"
RUN mv composer.phar /usr/local/bin/composer

# 環境変数設定
ENV COMPOSER_ALLOW_SUPERUSER 1
ENV COMPOSER_HOME "/opt/composer"
ENV PATH "$PATH:/opt/composer/vendor/bin"

# Laravelインストール
RUN composer global require "laravel/installer"

# Laravelプロジェクト作成
WORKDIR /var/www
RUN composer create-project laravel/laravel laravel

FROM php:7.3-alpine

# ビルド用コンテナから必要なコンテンツをコピー
COPY --from=vender /opt/composer/vendor/ /opt/vender/
COPY --from=vender /var/www/ /var/www/

# ポートを公開
EXPOSE 8000

# Laravelサーバーを実行
WORKDIR /var/www/laravel
CMD ["php","artisan","serve","--host","0.0.0.0"]

軽量化に際して覚えておくこと

マルチステージビルド

マルチステージビルドは、一般的にビルドに必要なコンテンツの生成フェーズと実行に必要なコンテンツに絞ってコンテナを固めるフェーズに分けてコンテナをビルドすることを指します。
ビルド時に必要だが実行時にには必要ない(一般的にDeveloperKitのような)ものを実行するコンテナから除外できるため、コンテナイメージの軽量化が期待できます。

squashオプション

Dockerfileでビルドする際、Step毎にコンテナのレイヤーが生成され、最終的なコンテナはそのレイヤーを含むためにサイズが肥大化しがちです。
ビルド時にsquashオプションを用いると、最終的にレイヤー1つに集約してくれるため、コンテナイメージの軽量化が期待できます。

Alpine Linux

詳細は割愛しますが、軽量OSとしてコンテナ界隈では有名です。
https://ja.wikipedia.org/wiki/Alpine_Linux

Alpine Linuxをベースとすることで、その他のイメージをベースとするよりも、コンテナイメージの軽量化が期待できます。

Dockerfile詳細

ビルド用イメージ

FROM amazonlinux:2 as vender

前回同様、AmazonLinux2をベースとしていますが、後段でしようするためにエイリアスとして as vender を付けています。

省略

# PHPインストール
# Composerインストール
# 環境変数設定
# Laravelインストール
# Laravelプロジェクト作成
# ポートを公開
# Laravelサーバーを実行

上記は前回と同じなため、解説を省略します。

実行用イメージ

FROM php:7.3-alpine

PHP公式から提供されているAlpineLinuxのイメージを使用します。
これによってAlpineLinux且つPHP7.3の環境を構築できます。

ビルド用コンテナから必要なコンテンツをコピー

COPY --from=vender /opt/composer/vendor/ /opt/vender/
COPY --from=vender /var/www/ /var/www/

前段のビルド用コンテナから必要なコンテンツをコピーします。
ここで前段で用いた、 as vender 効力を発揮します。

コンテナビルド

docker build -t laravel . --squash

ビルド時に --squash オプションを付加します。
これによってレイヤーを1つに集約し、計量化を図ります。

軽量化前と軽量化後の比較

軽量化前

docker images laravel
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
laravel         latest              xxxxxxxxxxxx         xx seconds ago        748MB

軽量化後

docker images laravel
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
laravel         latest              xxxxxxxxxxxx         xx seconds ago        117MB

まとめ

少しの工夫でコンテナが軽量化できることがわかっていただけたと思います。
最初にも述べたように、コンテナイメージサイズはコンテナ起動時間に直結するため、積極的に軽量化を図っていきたいですね。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む