20191020のlaravelに関する記事は2件です。

Vue.js + Laravelを使って英和辞書APIを使おう #1

英語版wikiを気軽に読みたい!

 Vue.js+Laravelで
・Mediawikiを用いてwikiの記事をHTMLで引っ張ってくる
・ハイライトとか単語検索機能をつける
・単語の登録機能(単語帳みたいなの)をつけて後で復習しやすいようにする
みたいなアプリが出来たらなーと思って現在実装しています。
 今回は単語検索機能について必死にググりながら実装していったものを記事にまとめます。

実際に作ったもの(開発中)
http://wiki-learning.herokuapp.com
GitHub
https://github.com/customaddone/wikiLearning

開発環境

使用ツール名 バージョン
Laravel 6.1.0
Vue 6.4.1

Laravelのバージョンごとにresources/jsのディレクトリの構造が異なったりするようです。

実装するもの

Vue(単一コンポーネント)

  • template
    • 検索結果を表示するカード(ボタンで表示/非表示の切り替え可)
    • カードの表示/非表示を切り替えるボタン
  • script
    • デ辞蔵(辞書API)で単語の検索、内容取得する機能

Laravel

  • Controller
    • デ辞蔵(辞書API)で単語の検索、内容取得する機能(Guzzleを用いる)

同一オリジンポリシー

 ブラウザには、同一オリジンポリシーというものが適用されていて、異なるドメイン(例localhost -> en.wikipedia...(wikiAPIのドメイン))にアクセスしようとすると、「access-control-allow-origin ヘッダーに見つかりません。」とのエラーが出て弾かれます。

 外部APIを使うということは、異なるドメイン(localhost -> 外部APIのドメイン)にアクセスしようとすることなので、何かしら対策をしないとアクセスを弾かれてAPIで外部APIからレスポンスを受け取れません。

 対策としては
1 Chromeの拡張機能を使う
2 サーバーサイド(Laravel側)でページを取得
3 Jsonpを利用する

などの方法があるらしく、今回は「2 サーバーサイド(Laravel側)でページを取得」で対応しようと思います。

Guzzle

PHPにはGuzzleというライブラリがあり、これを用いるとPHPでHTTPリクエストを行うことができます。これでクロスドメイン通信が可能になります。

インストール

Composerでインストールしましょう。
$ composer require guzzlehttp/guzzle

Vue側

単一コンポーネントのscriptの部分に書いていきましょう

resources/js/components/WikiShow.Vue
    /* デ辞蔵を使って単語検索->ヒットすればIDを取得して単語のページを検索
       Guzzleを使ってクロスオリジン通信を行う */
    researchAxios: function (word) {
      return new Promise((resolve, reject) => {
        axios.get("/api/data/" + word)
             .then((response) => {

               /* 戻ってきたデータからIDを取得 */
               var searchId = response.data.match(/(\d{6})/);
               this.searchWordId = searchId[0]

               /* IDを用いて単語のページを検索 */
               axios.get("/api/datashow/" + this.searchWordId)
                    .then((response) => {

                      var means = response.data.match(/<div>(.*?)<\/div>/);
                      this.translated = means[1];
                      resolve();
                    })
                    .catch(response => console.log(response));
              })
              .catch((response) => {

                console.log(response);
                reject();

              });
          });
    },

(Vueファイルはシンタックスハイライト効かなくて寂しい..)

この部分に注目してください。

axios.get("/api/data/" + word)
             .then((response) => {

axisのgetメソッドで(localhost~)/api/data/(word(検索したい語))のurlでLaravelにリクエストをしています。routes/api.phpにAPIのルーティングを設定しましょう。

routes/api.php
Route::get("/data/{pass}", "ArticlesController@dict"
);

先ほどのリクエストでArticlesControllerのdictメソッドを呼べるようにルーティングしました。dictメソッドを実装していきましょう。

Laravel側

ここでGuzzleを使います。

app/Http/Controllers/ArticlesController.php
<?php

namespace App\Http\Controllers;

use App\Article;
use Illuminate\Http\Request;
use GuzzleHttp\Client;

class ArticlesController extends Controller
{

    public function dict($pass)
    {
        $client = new \GuzzleHttp\Client();

        $response = $client->request(
            'GET',
            // レスポンスを返すurl(デ辞蔵のurl)
            $url = "http://public.dejizo.jp/NetDicV09.asmx/SearchDicItemLite",
            [ 'query' => [
                'Dic' => 'EJdict',
                'Word' => $pass,
                'Scope' => 'HEADWORD',
                'Match' => 'STARTWITH',
                'Merge' => 'AND',
                'Prof' => 'JSON',
                'PageSize' => 1,
                'PageIndex' => 0
            ]],
            // パラメーターがあれば設定
        );
        // レスポンスボディを取得
        $responseBody = $response->getBody()->getContents();
        return $responseBody;
    }
}
use GuzzleHttp\Client;

Clientインスタンスを使用できるようにして

$client = new \GuzzleHttp\Client();

インスタンスを生成

$response = $client->request(
    'GET',
    $url = "http://public.dejizo.jp/NetDicV09.asmx/SearchDicItemLite",
    [ 'query' => [
      'Dic' => 'EJdict',
      'Word' => $pass,
      'Scope' => 'HEADWORD',
      'Match' => 'STARTWITH',
      'Merge' => 'AND',
      'Prof' => 'JSON',
      'PageSize' => 1,
      'PageIndex' => 0
    ]],
// パラメーターがあれば設定
);

Vue側からパスの形で投げられたword + 各種検索条件をつけて$client->requestで指定のurlにリクエスト

// レスポンスボディを取得
$responseBody = $response->getBody()->getContents();
return $responseBody;

返ってきたレスポンスの内容を$responseBodyに収納してVue側にreturnする。

これでVue + Laravelで辞書APIを用いて入力した単語を検索する機能を
一通り実装できました。

次回はビューと検索機能をより使いやすくするための細かい実装について書いて行こうと思います。

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

LaravelでリダイレクトテストするとルートURLが返ってきてしまう

Laravel で、->assertredirect() を使ってPOST後に指定したページにリダイレクトできているかテストしようとした。
画面上では問題なく動作するのに、テストでは想定外のURLにリダイレクトしてしまう現象が起こり、少しハマった。

環境

Laravel 6.2.0

うまくいかなかったテスト

記事を投稿をするテスト

public function testCreatePost()
    {
        $response = $this
            ->post('post/create', [
                'title' => 'sample title'
                'text' => 'sample text'
            ])

        $response->assertRedirect('posts');
    }

テスト結果

There was 1 failure:

1) Tests\Feature\Owner\IncentivesControllerTest::testRedirect
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'https://localhost/posts'
+'https://localhost'

画面上の動作でははちゃんと /posts にリダイレクトされてるのに、なぜルートURLに飛ばされることになってる??

原因

リダイレクトテストをしたとき、back() で前の画面に戻されるが、テストの仕様上、前の画面は保存されていない。
よって、ルートURLの https://localhost が返されてしまう。

対策

->from() で前の画面を指定(リファラーを定義)する必要があった。

public function testCreatePost()
    {
        $response = $this
            ->from('posts') //追加
            ->post('post/create', [
                'title' => 'sample title'
                'text' => 'sample text'
            ])

        $response->assertRedirect('posts');
    }

これでうまくテストが通った!

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