毎月恒例!#ProLabo(プロラボ)渋谷もくもく会@渋谷1月12日(土)に開催しました! 

こんにちは! ITプロパートナーズ(https://itpropartners.jp/)インターン栗岡です!

普段は、Laravelで自社サービスの開発をしたり、新卒採用関係の業務をやっています。

今回は、1月12日に弊社渋谷オフィスで開催されたもくもく会をレポートします!

続きを読む

Nuxt.js + QiitaAPIで開発したWebアプリケーションをFirebaseにデプロイする

こんにちは。

ITプロパートナーズでエンジニアの米川(@keiuwk0614)です。

 

普段は、自社プロダクトである中途向けの転職サービスGraspy(https://graspy.jp/)の開発をしています。フロントエンドはNuxt.js、サーバサイドはLaravelを使用し開発しています。

今回は、初学者向けにNuxtのプロジェクト作成から、外部APIを呼び出して簡単なWebアプリケーションを開発し、Firebaseのホスティングにデプロイするまでを紹介していきたいと思います。

f:id:itpro_yonekawa:20181212172913p:plain

 

 

実行環境

  • node v10.3.0
  • yarn 1.9.4
  • nuxt 2.0.0
  • firebase CLI 5.0.1

 1. Nuxtプロジェクト作成

1-1. プロジェクト作成

プロジェクトを作成するディレクトリに移動し、公式ドキュメント(インストール - Nuxt.js)にならい下記コマンドを実行します。

※今回はyarnを使用

yarnが入っていない方は yarnを使ってみた - Qiita  を参照してください。

$ yarn create nuxt-app <my-project> 

 いくつか質問されます 。

    ※今回は、UI frameworkにbulma、rendering modeはUniversal、axios moduleを使用するのでyesで選択してください。

? Project name nuxt-firebase
? Project description My tiptop Nuxt.js project
? Use a custom server framework none
? Use a custom UI framework bulma
? Choose rendering mode Universal
? Use axios module yes
? Use eslint no
? Use prettier no
? Author name kei yonekawa
? Choose a package manager yarn

選択後、全ての依存関係がインストールされプロジェクトが作成されます。

 

1-2.  起動

作成したプロジェクトのディレクトリに移動し、下記コマンドを実行します。

$ yarn run dev

デフォルトで3000番ポートが開きます。 http://localhost:3000 でアクセスし下記画面が表示されれば成功です。

f:id:itpro_yonekawa:20181211235205p:plain

デフォルトのポート番号を変更したい場合は、package.jsonのdevの引数にポートを指定するか、

"scripts": {
"dev": "nuxt --port 3333",
}

nuxt.confing.js内に設定することで変更できます。

module.exports = {
server: {
port: 8888,
},
// その他設定
}

 

2. axiosでQiita APIを呼び出す

2-1. 使用するQiita API

今回使用するのは、GET /api/v2/items という記事の一覧を作成日時の降順で返却するAPIを使用します。詳細は下記のAPI仕様書をご確認ください。

qiita.com

 

2-2. ayncData内でqiita apiを呼び出す

 その前にasyncDataには次のような機能があります。

 

ページコンポーネントがロードされる前に毎回呼び出される

・サーバサイドレンダリングや、ページ遷移前にも呼び出される

・contextを引数にとる

・asyncDataの結果は、dataとマージされる

 

asyncDataと似たようなメソッドに、fetchというメソッドもあります。

fetchもasyncDataもほぼほぼ機能は同じですが、asyncDataの場合はdataとマージされるため、必ずプロパティをreturnする必要があります。取得したデータをvuexに入れて使用する場合はfetchを使用し、ページコンポーネント内で使用する場合はasyncDataを使用するのが良さそうです。

 

それでは、プロジェクト作成時にデフォルトで生成されたpages/index.vueを編集します。今回は、apiで取得した結果をそのままページコンポーネント内で使用するため、asyncData内でapiを呼び出します。

<script>
// axios
import axios from 'axios';
// qiita api URL
const BASE_URL = 'https://qiita.com/api/v2/';

export default {
async asyncData(context) {
try {
const response = await axios.get(BASE_URL + 'items', {
params: {
page: 1,
per_page: 10,
}
});
return {
articleList: response.data,
};
} catch (error) {
console.log(error);
}
}
}
</script>

/api/v2/itemsAPIには次のパラメータが設定できます。

  • page ページ番号 (1から100まで)
  • per_page 1ページあたりに含まれる要素数 (1から100まで)
  • query 検索クエリ

今回は、10件のデータを取得してくるように固定で設定します。

何かキーワード検索したい場合は、queryというパラメータに検索したいキーワードを設定することも可能です。

params: {
page: 1,
per_page: 10,
query: 'Nuxt.js',
}

 

2-3. apiのレスポンス結果を画面に表示

2-2ではasyncData内でapiを呼び、レスポンス結果をarticleListに設定してreturnしています。先ほども述べたように、asyncDataの結果はdataとマージされるため、pages/index.vueでarticleListを展開していきます。

articleListをv-forでループし、記事のタイトル、記事URL、アイコン画像、ユーザーID、いいね数を表示します。

レスポンスには他にも本文、タグ、更新日など様々あります。必要に応じカスタマイズしてください。

まずは、下記のコードをコピペでOKです。

<template>
<section>
<article
v-for="(article, index) in articleList"
:key="index"
class="box media">
<figure class="media-left">
<p class="image is-64x64">
<img :src="article.user.profile_image_url">
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
<
strong><nuxt-link :to="article.url">{{ article.title}}</nuxt-link></strong> <br>
{{ article.user.id }}<br>
<small>Like · {{ article.likes_count }}</small>
</p>
</div>
</div>
</article>
</section>
</template>

 

ブラウザに戻り、上記コードコピペしていれば次のような画面が表示されていると思います。

 

 

f:id:itpro_yonekawa:20181212234848p:plain

 

これで一旦、Qiita APIを呼び出し記事の一覧を表示するところまでは完了になります。

コンポーネントの切り出し、デザイン等は各自でカスタマイズして貰えればと思います。

 

3. Firebase Hostingにデプロイ

3-1. Firebaseの準備

Firebase Console(https://console.firebase.google.com/?hl=ja)にアクセスし、googleアカウントでログインします。

f:id:itpro_yonekawa:20181213001128p:plain

プロジェクト、ロケーションの設定、規約に同意しプロジェクトを作成を押下します。

自動でFirebaseの管理画面に遷移します。

f:id:itpro_yonekawa:20181213001208p:plain

 

3-2. Firebase Hostingにデプロイ

3-2-1. Firebase CLIをインストール

先ほど作成したプロジェクトのディレクトリで、Firebase CLIをインストールしFirebaseコマンドを使用できるようにします。

$ yarn global add firebase-tools
3-2-2. firebaseにログイン

下記のコマンドを実行し、firebaseにログインします。

このコマンドを実行するとローカルコンピュータがFirebaseアカウントに接続され、プロジェクトへのアクセス権が付与されます。

$ firebase login
 3-2-3. firebaseのホスティングの初期設定

下記コマンドを実行し、ホスティングの初期設定を行います。

$ firebase init hosting

先ほど作成したfirebaseプロジェクトを選択します。

? Select a default Firebase Project for this directory: nuxt-tutorial(nuxt-tutorial-491c1)

公開ディレクトリはdistにします。

? What do you want to use as your public directory ? dist

SPAとして公開するか聞かれますが、今回はasyncDataを使用しSSRしているのでNoを入力します。

? Configure as a single-page app (rewrite all urls to /index.html)? No

プロジェクト直下にfirebase.jsonと.firebasercというファイルが自動で作られます。

 

 3-2-4. firebase デプロイ

 下記コマンドを実行します。

 dist/ 配下に静的ファイルが生成されます。

$ yarn build

本番環境に公開します。

$ firebase deploy

無事にデプロイできましたでしょうか。

firebase Hostingのダッシュボードでデプロイが成功したか、デプロイ先のドメインが分かります。

f:id:itpro_yonekawa:20181225171535p:plain

 

 

筆者がデプロイしたものは下記のURLからご確認頂けます。

https://nuxt-tutorial-491c1.firebaseapp.com/

 

 

今回作成したコードは、githubに公開していますので全体を見たい人はこちらを参考にしてください。

GitHub - keiyonekawa0614/nuxt-firebase: nuxt + qiita API + firebase hosting sample

 

ちょっと応用してキーワード検索できるものも作ってみました。

daryl-f5622.firebaseapp.com

こちらもgithubソースコードを公開しておりますので、参考にしてみてください。

GitHub - keiyonekawa0614/nuxt-tutorial: Web service to search qiita articles.


 

 最後に

ITプロパートナーズでは、Laravel、vue.js、Nuxt.jsで開発に挑戦したいエンジニア・デザイナーを絶賛募集中です。少しでも興味のある方は、DMでもGraspy、Wantedlyでもお気軽にご連絡頂けますと嬉しいです。お待ちしております。

 

 

サービスの管理画面で Vue + element.ui を活用する(table編)

ITプロパートナーズの新卒採用サービス「intee」のエンジニアの五藤です。

intee.jp

inteeの技術スタックは、バックエンドがPHP(CakePHP3)、フロントエンドがVue.jsを採用しています。 ユーザーが見る画面はもちろんの事、弊社スタッフが利用する管理画面に関しても、新しく実装する画面に関してはほとんどVueを使って管理画面を構築しています。

「何で管理画面のフロントエンドをリッチにする必要が?」

って思われるかもしれませんが、管理オペレーションが複雑になってくると、

  • 一度に複数のユーザーに対して操作したり、複数のレコードを追加する際にいちいち画面遷移したくない
  • 複雑なリレーションのデータ登録を、モーダルなどを用いて効率的にやりたい

などなど、オペレーション最適化の面で、リッチなフロントエンドを提供するメリットは意外と多く、営業サイドから 「この画面をVueを使ってサクサク使えるようにしてほしい」 という要望を受けることもしばしばだったります。

そんな中で、UI/コンポーネントライブラリとして愛用しているのが、Element です!

Element

各種フォーム部品やモーダルやアラート、簡単なグラフ表示などの、リッチな画面を作るのに必要なコンポーネントが揃っているニクいやつです。しかも、Vueのコンポーネントとして実装されているため、

<el-tag type="success">Elementに用意されてるめっちゃきれいなタグUI</el-tag>

という感じに、HTMLライクな書き方で簡単にコンポーネントを配置できるのも嬉しいところです。

今回は、その中でも、管理画面の画面設計の中核を占める <el-table> の使い方や、実装上のポイントについてまとめます!

tableコンポーネントてどんなの?

スクリーンショット 2018-11-28 10.07.36.pngelement-ui公式 より引用 )

簡単に言うと、管理画面でよくある、「データ一覧をテーブル形式で表示する」事ができるコンポーネントです。 これだけ書くと凄くシンプルなので、elementのtableのすごい所をガンガン紹介します!

el-tableを使うと捗るポイント

データ投入が簡単で、いい感じに表示してくれる

データ設定の方法は簡単で、配列形式のデータをVueのdata属性に格納して、<el-table> のプロパティとして指定するだけ。

(データ側)

data: {
          tableData: [{
            date: '2016-05-03',
            name: 'Tom',
            address: 'No. 189, Grove St, Los Angeles'
          }, {
            date: '2016-05-02',
            name: 'Tom',
            address: 'No. 189, Grove St, Los Angeles'
          }, {
            date: '2016-05-04',
            name: 'Tom',
            address: 'No. 189, Grove St, Los Angeles'
          }, {
            date: '2016-05-01',
            name: 'Tom',
            address: 'No. 189, Grove St, Los Angeles'
          }]
        }

(コンポーネント)

<el-table :data="tableData">

これだけで、tableDataプロパティに格納した配列データを、<el-table>内で使用することが出来ますし、el-dataの値を切り替えれば、リアルタイムでテーブル上の値も更新されます。

また、dataに格納する値は、

<el-table :data="tableData">

      <!-- 日付データを表示するカラム -->     
      <el-table-column
        prop="date"
        label="Date"
        width="180">
      </el-table-column>

      <!-- 名前データを表示するカラム -->
      <el-table-column
        prop="name"
        label="Name"
        width="180">
      </el-table-column>

<el-table>

という感じで、table側で自由に各カラムを抽出、表示できます。 dataに設定された全カラムが勝手に出力されるのではなく、コンポーネント側で出したい情報を自由にピックできる のがポイントで、実際の想定シーンとしては、

  • dataプロパティには、サーバーサイド側の参照APIをまるっと格納させ、<el-table>側で、必要なデータを必要な形でレイアウトする

というやり方で、 汎用的なAjaxの戻り値を、そのまま<el-table>にぶちこめる のが実装上は凄く楽だったりします。

各カラムの表示内容が、タグベースで柔軟に設定できる

各カラムに表示する値は、HTML形式で動的に設定可能で、更に言うと、他のelementのコンポーネントを配置することも出来ます。

[いろんなタグを配置してみるとこんな感じ]

f:id:itpro_goto:20181203220644p:plain
いろんなタグを配置してみた

こんな感じで、画像やアイコン、タグ、ボタンなどを各カラムにポチポチ配置して、可読性の高い画面をデザイナー抜きで簡単に作ることが出来ちゃいます。 もちろんボタンに導線を作ることもできるので、

  • ボタンを押すとチェックリストにチェックが付く
  • ボタンを押すとモーダルを表示してデータ編集ができる

といった処理を組むことも簡単です。 ちなみにモーダルもelementで用意されています。

http://element.eleme.io/#/en-US/component/dialog

いたれりつくせりですね。

・・・どうですか?管理画面に<el-table>使いたくなりませんか?

実際に使う上でのtips

<el-table>の素晴らしさがわかったところで、実際に作っていく上でのポイントをいくつか書いていきます。

基本的なデータフロー

前項でも述べましたが、<el-table>に格納するデータは、Ajaxの戻り値をそのまま格納するのがわかりやすいので、 「データを取得する共通処理」を一つの共通メソッドにまとめておき、表示・更新したいタイミングで呼び出す のが基本的な実装パターンになります。以下はデータ読み込み処理のコード例です。

// レコード取得を実施
getModels:function(){
  var that = this
  this.isLoading = true // (1)ローディング表示をON
  $.ajax({ // jQuery ajax使ってますが他のライブラリでも対して変わらないはず
    url:this.apiUrl,
    type:'GET',
    data:this.condition // (2)GETパラメータをプロパティ
  }).done(function(data){
    // API戻り値をtableDataに格納
    that.tableData = data.models 
    that.isLoading = false
  })
},

いくつかポイントを上げると、

  • APIを呼び出すタイミングでローディング用のプロパティをONにし、読み込み後にOFFにすることでローディングを実装
    • ローディングステータスは<el-table v-loading="loading"> という感じで、v-loadingディレクティブにbindすることで、プロパティと同期できます。
  • 検索クエリとページネーションはプロパティにまとめておくと、そのまま渡せる(検索ボックス側でthis.conditionを編集する作りにすると、検索側と読み込み側が疎結合になるので扱いやすい

という感じです。

データ表示の基本2タイプ

表示カラムは<el-table-column> を使うといいましたが、2つの記法があります。

el-table-column::prop で簡単カラム指定

<el-table-column prop="full_name" label="氏名">
</el-table-column>

propプロパティに直接Objectのキーを指定すると、文字列としてデータが表示されます。

template slot-scope="scope" で細かく指定

もう少しリッチに各カラムのデータを書きたい場合は、このように書きます。

<el-table-column label="タグ一覧">
  <template slot-scope="scope">
       <el-tag v-for="tag in scope.row.tags" :key="tag.id" type="success">{{tag.name}}<el-tag>    
  </temlate>    
</el-table-column>

ポイントとしては

  • <template slot-scope="scope"> で囲んだ中に、そのカラムで表示したいHTMLを配置
  • scope.row.[カラム名] で各レコードの情報が参照できる

です。このやり方を使うと、カラムの中で自由にレコード情報を表示ことができるため、 先程あげたような

f:id:itpro_goto:20181203220644p:plain

  • 画像を貼り付けたり
  • カラム内で改行して複数の情報を表示したり
  • アクションボタンを配置したり

とかなり応用が効くようになります。

テーブルの行番号を取得したい。

行番号は scope.$index で取得できます。

<el-table-column width="50" fixed>
  <template slot-scope="scope" label="No">
    {{ scope.$index}}
  </template>
</el-table-column>

発展パターンとして、ページネーションを実装している場合のレコード番号は、

<el-table-column width="50" fixed>
  <template slot-scope="scope" label="No">
    {{ getRecordSequence(scope.$index)}}
  </template>
</el-table-column>

というふうに外部メソッドにscope.$index を投げて、

getRecordSequence(index){
  if(!this.paginate.page || !this.paginate.perPage){
    return index + 1
  }
  return (this.paginate.page - 1) * this.paginate.perPage + index + 1
},

こんな感じで、ページネーションの値と組み合わせて算出したりもします。

ページネーション

<el-table> はページングのための特別な仕組みを持たないため、

  • dataプロパティに「ページ情報」と「総ページ数」を用意しておき、API更新のタイミングで同期する
  • 画面側のページング表示、操作は<el-paginate> コンポーネントを別途配置して、こちらもAPI更新と紐付ける

というやり方で実装します。

データ構造

data:{
  condition:{
    page: 1, // 現在のページ数(conditionに含めることでクエリパラメータとして渡される
  },
  pageCount: 1, //ページ数を取得
},
methods: {
  getModels:function(){
    var that = this
    $.ajax({ // jQuery ajax使ってますが他のライブラリでも対して変わらないはず
      url:this.apiUrl,
      type:'GET',
      data:this.condition 
  }).done(function(data){
    that.tableData = data.models 
    that.isLoading = false
    that.pageCount = data.paginate.pageCount //総ページ情報を更新
    that.paginate = data.paginate //現在ページ情報を更新
  })
},
            }

ページネーション部品

<el-pagination
  @current-change = "getModels"
  :current-page.sync="condition.page"
  :page-count="pageCount">
</el-pagination>

通化のパターン

いろいろな画面で<el-table>を使うようになってくると、必要な処理を共通化したい!と思う人もいるかも知れません。結論からいうと、共通化はcomponentよりもmixinで行うのが個人的にはおすすめです。 mixin側で、

  • APIとの通信処理
  • 取得したレコード一覧や検索条件、ページネーションを保持するためのdataオブジェクト

を共通化して持っておくと、このパターンのテーブル表示を量産する上では役に立ちます。 こんな感じでしょうか。

// 管理画面の汎用テーブルプラグイン

var dataTableMixin = {
    data:{
        getUrl: '/get', // データ取得用のAPI。必要に応じて実装側でオーバーライドする。
        models: [], // 取得されたレコード配列を保持
        // 検索条件を保持。値を変更することで、レコード取得APIにリクエストクエリとして渡される
        condition:{
            page: 1, // ページ情報も検索条件の一つとして保持する
        },
        pageCount: 1, // APIから返却された総ページ数の値を保持
        isLoading: false // ローディング状態を保持
    },
    mounted:function(){
        this.getModels()
    },
    methods:{
        // ページネーション切り替え
        changeCurrentPage: function(page){
           this.condition.page = page
           this.getModels()
        },

        // レコード取得を実施
        getModels:function(){
            var that = this
            this.isLoading = true
            $.ajax({ // jQuery ajax使ってますが他のライブラリでも対して変わらないはず
                url:this.getUrl,
                type:'GET',
                data:this.condition
            }).done(function(data){
                that.models = data.models
                that.isLoading = false
                // ページネーション関連情報をセット
                that.pageCount = data.paginate.pageCount
                that.paginate = data.paginate
                that.afterGet()
            })
        },
        // レコード取得後に独自処理を追加するためのフックメソッド
        afterGet:function(){
            return //OVERRIDE ME
        },
    }
}

いかがでしたでしょうか?ぜひ管理画面もリッチな <el-table> をご活用ください!

毎月恒例!#ProLabo(プロラボ)もくもく会を@渋谷11月25日(土)に開催しました! 

こんにちは! ITプロパートナーズ(https://itpropartners.jp/)インターン栗岡です!

普段は、Laravelで自社サービスの開発をしたり、新卒採用関係の業務をやっています。

今回は、11月25日に弊社渋谷オフィスで開催されたもくもく会をレポートします!

続きを読む

【Laravel】コマンドアプリケーションで行うデータ移行

さなぽんです。社内ではマッチングサービスを中心とした受託案件のお仕事をしています。
Twitterは例のサングラススパムに乗っ取られて凍結されてしまいました。。。とほほ。


お仕事はCakePHP2や3を中心に、最近はLaravelも使い始めました。
弊社サービス「ITプロパートナーズ」に登録いただいたエンジニアの方とチームで動きディレクション中心に行ったり
自分ひとりであのフレームワークは…こっちだと…などと手を動かしたりもしています。


お客様からシステムのリプレイス案件のお声掛けをいただくことも多々あります。
本当にありがたい限りです。

リプレイスするにあたり、サーバーや言語のバージョンアップ、フレームワークを変更して再コーディングを行う以外に
データベースの再設計を検討することもよくあるお話です。


再設計をして、いざ、データ移行!となるのですが、これが思いの外面倒な作業となる事が多々あります。
SQLを用意し作業をしていると、条件分岐やループはPL/SQLだと便利なのにな、、、なんて思ってしまうこともありますね。


そこで今日紹介するのは、コマンドライン処理を使ってデータ移行を行うやり方です。
この仕組みもITプロパートナーズに登録いただいたエンジニアさんが作っていただいたものになります。


まずはクラスを作成します。以下のコマンドを実行してみましよう。

$ php artisan make:command Migrate

実行後、app/Console/Commands配下に以下のクラスが作成されているはずです。

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class Migrate extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:name';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //
    }
}

$signatureには実行時のコマンド名、$descriptionにはコマンドの説明をそれぞれ設定します。
例えば以下のように設定をします。

    protected $signature = 'migrate:exec';
    protected $description = 'データ移行実行';

その後、artisan listを実行すると、、、

$ php artisan list

Laravel Framework 5.6.38

Usage:
  command [options] [arguments]

… 略

 migrate
  migrate:exec           データ移行実行

表示されました!
これで php artisan migrate:exec とコマンドを叩くとMigrateクラスが実行されることになります。


引き続き、処理を書いていきましょう!
処理は handle() に記述していきます。

<?php

namespace App\Console\Commands;

use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

… 略

public function handle()
{
    DB::transaction(function () {
        $this->migrate();
        $this->seed();
    });
    return true;
}

private function migrate()
{
    $this->progress('dropTables');
    $this->progress('callMigrate');
}

private function progress($func, $message = null)
{
    $this->_bar->setMessage($message ?? snake_case($func, ' '));
    $this->$func();
    $this->_bar->advance();
}

private function dropTables()
{
    foreach (\DB::select('SHOW TABLES') as $table) {
        $column_name = 'Tables_in_' . \DB::connection('')->getDatabaseName();
        \DB::statement('DROP TABLE IF EXISTS `' . $table->$column_name . '`');
    }
}

private function callMigrate()
{
    \Artisan::call('migrate');
}

private function seed()
{
    foreach ($this->getSeedFunc() as $item) {
        $this->progress($item);
    }
}

private function getSeedFunc()
{
    return [
        'seedCompany',
    ];
}

private function seedCompany()
{
    foreach (DB::connection('old_db')->table('company')->select()->cursor() as $item) {
        DB::table('companies')->insert([
            'id'                 => $item->id,
            'name'           => $item->name,
            'zipcode'       => $item->zipcode,
            'address'       => $item->address,
            'tel'                 => $item->tel,
        ]);
    }
}

一気に書いてしまいました笑
旧DBのcompanyテーブルから新DBのcompaniesテーブルにデータを移行します。
この中でif文などの制御はもちろん、複雑な処理も行う事ができます。

また、処理の中で旧DBからデータを取得しますので、 config/database.php ファイルに旧DBの情報も記述します。

'old_db' => [
    'driver' => 'mysql',
    'host' => env('DB_OLD_HOST', '127.0.0.1'),
    'port' => env('DB_OLD_PORT', '3306'),
    'database' => env('DB_OLD_DATABASE', 'forge'),
    'username' => env('DB_OLDP_USERNAME', 'forge'),
    'password' => env('DB_OLD_PASSWORD', ''),
    'unix_socket' => env('DB_OLD_SOCKET', ''),
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'strict' => true,
    'engine' => null,
],

DB_OLD_xxx の内容は .env ファイルにて設定します。

これでひとまず動くかと思いますので、是非試してみてください。


ここからは宣伝です。
12月1日(土)に「起業家」と「ITプロフェッショナル」の出会いを創出する
ビジネスコンテスト『HATCH』を行います。
観覧者を大募集していますので、興味のある方は是非お越しください!

itpro.connpass.com


12月18日(火)にSIerやSESからWEBエンジニアへのキャリアチェンジをテーマにしたイベントを開催します。
ワタクシが司会をする予定です。こちらもよろしくお願いします。

itpropartners.connpass.com

【Nuxt.js・Laravel】5分でわかる!Nuxt.jsの基本機能を使ってLP+お問い合わせページをつくってみよう

f:id:tomita_ak:20181122200152j:plain

こんにちは。エンジニアのとみ(@tom_a417468)と申します。

いよいよ今年も残り1ヶ月ですね

今年何かと話題のNuxt.js(vue.js)とLaravelを使い、お問い合わせページと管理画面を作成した時のTipsのようなものをまとめました。

これからやってみようかな、という方の参考になれば嬉しいです。

ディレクトリ構成

Nuxtで作成したLPと問い合わせフォーム画面があるプロジェクト、Laravelで作成した管理画面のプロジェクトのディレクトリを作成しました。

Gitリポジトリは同一にしています。

project/
├── lp/
└── admin/

LPはNuxt.js、adminはLaravelを使用しています。

Nuxtに関しては、ほぼvueの基本機能で賄えてしまっていますが。。

開発環境

Dockerを使用しました。一つのコンテナにポートを2つ空け、どちらにアクセスしたかで表示を出し分けています。

その他

HTMLはpugcsssassを使いました。

vueファイル内では"template"や"style"タグで指定することで、切り替えが簡単に行えます。

pugの場合

<template lang="pug">

sassの場合

<style lang="sass">

pugは閉じタグが無く、以下のように書くと...

div.content
    span.mark チェック

このように生成されます!

<div class="content">
<span class="mark">チェック</span>
</div>

コードも綺麗に書けますし、閉じタグの記述が要らないのはとても便利ですよね。

(しかし外部を含むチーム開発への導入の場合、学習コストのハードルが高くHTMLにやむなく切り替えた、という話もあるようですが...😢)

ページ構成

大まかに書くとこのような構成です。とてもシンプル。

LP

・LP
・入力画面
・確認画面
・完了画面

管理画面

・ログイン
・一覧画面
・検索結果画面

画面遷移

入力画面

・v-for

複数の選択項目はv-forでfor文のように出力できます。

label.radio(v-for="genderLabel in genderLabels" :key="genderLabel.id")
input(type='radio', name='gender', v-bind:value='genderLabel', v-model='data.gender')
| {{ genderLabel.value }}

(※Nuxtの最新のバージョンでは:keyの指定が必須のようです)

 

・import { } from ''

さらにimportfromで外部のjsファイルから項目内容を読み込むことができます。

import { genderLabels } from '~/enums/enums.js'

importしたjsはこのような中身。

export const genderLabels = [
{ id: 1, value: '男性' },
{ id: 2, value: '女性' }
];

 

・vuelidate
vue.jsプラグインのvuelidatehttps://monterail.github.io/vuelidate/を使い、必須項目が入力されていない場合はv-ifでエラー文を表示させています。

Name: {required},

Nameが入力されない場合、p.errorが表示されます。

p.error(v-if="$v.data.Name.$error") お名前は必ずご入力下さい。

 

・v-model

入力画面でフォームに入力した値をv-modelに保持します。

input.input(type='text', v-model='data.Name', placeholder='名前')

 

確認画面
確認画面では以下のような書き方で、v-modelに保持したデータを呼び出しました。

p {{ data.Name }}

 

・@click、nuxt-link

@click.native(確認画面で送信ボタンをクリックする時)に、postイベントを発火(APIを送信)します。

同時に、nuxt-link(to='')で完了画面へ遷移させます。

nuxt-link(@click.native='post' to='/complete') 送信する

 

・axios.post
axios.postフォームに入力した値をpostDataにまとめて、API送信します。

axios.post('http://laravelProject/api/users', postData)

 

Laravelプロジェクト側
ここで、APIから受け取った値をDBへインサートします。

$user = new User();$user->fill($formData)->save();

問い合わせを行ったユーザー、管理者へメール送信します。

Mail::to($user['email_address'])->send(new UserEmail($user));

 

管理画面

ログインの他に、閲覧・検索等の機能を持たせるため、Laravel Scaffoldパッケージを使いました。画面の生成とCRUDがコマンドで作成できて便利でした!composerで導入できます。

composer require 'laralib/l5scaffold' --dev

 

(特に)ハマったこと

Nuxtの起動でハマりました。開発環境ではnpm run devでの起動で充分なのですが、本番環境ではforeverコマンドを使ってアプリケーションを起動したままにしないと、しばらく経つと通信が途切れてしまいます...。

感想

初めてvue.jsを使って入力画面→確認画面へ画面遷移がとても早く"フロントを触っている"実感があり、とても楽しかったです!

個人的にはCSSアニメーションを加えて、年代問わず分かりやすく使いやすいサービスを作ってみたいなあ、と思っています。来年はもっと開発します💪


最後に

ITプロパートナーズでは、Laravel、vue.js、Nuxt.jsで開発に挑戦したいエンジニア・デザイナーを絶賛募集中です!

www.wantedly.com


12月ではSIerやSESからWEBエンジニアへのキャリアチェンジをテーマにしたイベントも開催します!

itpropartners.connpass.com

採用以外でも、様々なイベントを開催予定です!もくもく会、キャリアを考える会、フリーランスの方のコミュニティ会、12月には新サービス「Graspy」のプレミア勉強会(講師陣がめちゃくちゃ豪華です!)など...ご興味のあるイベントがあれば、ぜひオフィスに遊びに来てください😄

itpropartners.connpass.com

graspy.jp

【ちょっと早いけど】2018年のLaravelまとめ

こんにちわ、ITプロパートナーズのエンジニアのくまモンエンジニア(@miyakey7)です。

Laravel駆動転職(LDJC)により今年1月にITプロパートナーズにジョインしました。

初めて実務でLaravelを使った開発を行い、あっという間に11月になってしまいました。

 

そうですね、気になりますよね?

2018年、Laravelにはどんな変化があったのか気になりますよね?

 

今回は少し早いですが2018年のLaravelに関する出来事や気になる変更点などを自分なりにピックアップして書きます!

(11月以降は随時追記していきたいと思いますw)

  

 

2018年1月のLaravel

Laravel 5.5.29→33

①ModelにqualifyColumn()メソッドが追加されました

このメソッドは引数で指定したカラム名をモデルのテーブルで修飾します。

// 元々の記述
$this->getTable().'.'.$this->getKeyName();

// qualifyColumnを使った記法
$this->qualifyColumn($this->getKeyName()) ;
// 使用例      $article->qualifyColumn('title'); // -> articles.title

使った事無いという方、Eloquent内でしっかり動いております!

気になる方は以下を確認ください!

github.com 

②query builderにdoesntExists()メソッドが追加され...マジか

そうですねexists()はよく使うのですが5.5.33より、doesntExists()が追加されております!

ちなみに一瞬notExists()という名前になりそうでした。 

 

if( !User::where('email', 'user@example.com')->exists() ){
}



if( User::where('email', 'user@example.com')->doesntExists(){
}

github.com

③ModelのwithTrashed()メソッドに引数指定が追加されました

withTrashed()メソッドは論理削除したデータを取得データに含める場合に使用します。

今回の変更により、元々以下のようにフラグで切り分けて使っていたのを

public function index(Request $request)
{
    $query = User::query();

    if ($request->showDeleted) {
        $query->withTrashed();
    }

    return $query->get();
}

下記のようにwithTrashed()メソッドの引数に依存して使用する/しないを切り替える事が出来ます。

public function index(Request $request)
{
    return User::withTrashed($request->showDeleted)->get();
}

 

2018年2月のLaravel

Laracon Online 2018

「Laracon Online 2018」が開催されました!

Laravelのオンラインカンファレンスは毎年開催されています!

今年の目玉はやはり、Laravel 5.6のリリースでした!

laracon.net

Laravel 5.6 Release

①log機能が改良されました

logging.phpが追加され、より細かい設定を行う事ができるようになりました。

カスタマイズで簡単にslackにログを通知することも出来ます。

 

チャンネルに「slack」を指定

'stack' => [
    'driver' => 'stack',
    'name' => 'channel-name',
    'channels' => ['single', 'slack'],
],

 

チャンネル設定で「slack」の設定を記述。下記の場合クリティカルレベルのログのみslackに通知する事が出来ます。

'channels' => [
   'slack' => [
        'driver' => 'slack',
        'url' => env('LOG_SLACK_WEBHOOK_URL'),
        'username' => 'Log通知',
        'emoji' => '',
        'level' => 'critical',
    ],
],
②Eloquentの日付データのキャスト機能追加されました

$castsを定義することで取得時指定したデータ形式にキャストされます。

protected $casts = [
    'birthday' => '誕生日:Y-m-d',
    'logined_at' => 'datetime:Y-m-d H:00',
];
③Blade Componentにエイリアス名が付けれるようになりました

resources/views/components/alert.blade.phpに以下のような記述をします。

<div class="alert alert-danger">
{{ $slot }}
</div>

AppServiceProviderのbootに以下のような記載をします。

Blade::component('components.alert', 'alert');

以下のように記述することが出来ます!

@component('alert')
    <p>アラートメッセージ</p>
@endcomponent

// 以下のような省略も出来ます
 @alert <p>アラートメッセージ</p> @endalert
④bootstrap4対応になりました

時代は4ですね。

⑤署名付きURLの発行がURL Generationの機能に追加

使い方は以下にまとめてあります!

qiita.com

Under Construction Package(4桁数字認証用パッケージ)

4桁数字認証を簡単に実装できるパッケージが公開されました。

5.6以降から使えます。

laravel-news.com

 使い方は以下にまとめてあります!

qiita.com

 

2018年3月のLaravel

Laravel 5.6.7→13

MySQLのsounds likeがサポートされました

以下の書き方で利用できます。

$query->where('name', 'sounds like', 'John Doe');
②@dumpがbladeに実装されました

元々あった@ddとの違いは、処理が止まらないことですね。

github.com

③Mailablesによるメールへの添付ファイル設定が簡単に行えるようになりました

④query builder のメソッドにが追加されましした

orWhereDay()orWhereMonth()orWhereYear()が追加されました。

\App\User::whereDay('updated_at', '=', 1)
    ->orWhereDay('updated_at', '=', 2); 
⑤bladeに@elseauth()@elseguestが追加されました

bladeでの切り分けが容易にできます。

@auth('administrator')
<p>管理者</p> @elseauth('standard')
<p>一般ユーザー</p>
@endauth

@guest('user')
<p>ゲストユーザー</p> @elseguest('subUser')
<p>サブゲストユーザー</p>
@endauth
⑥セキュリティパッチがリリースされました

Laravel 5.6.15と5.5.40が対策版のバージョンになります。

laravel-news.com

Laravel meetup Tokyo Vol.10開催

10回目で初参加しました。とても勉強になりモチベーションが上がる楽しいmeetupです。

laravel-meetup-tokyo.connpass.com

2018年4月のLaravel

Laravel 5.6.16→19

サブクエリ用のメソッドが追加されました!

joinSub()leftJoinSub()rightJoinSub()、が追加されました。

元々は以下のようにDB::raw()を使うやり方をしていました。

$query = DB::table('subtable');
$sql = '(' . $query->toSql() . ') as "sub"';
DB::table('table')->join(DB::raw($sql), ...);

 それが以下のように書けるようになりました。

DB::table('table')->joinSub('select * from "subtable"', 'sub', ...);
DB::table('table')->leftJoinSub(function ($q) { $q->from('subtable'); }, 'sub', ...);
DB::table('table')->rightJoinSub(DB::table('subtable')->where('foo', 'bar'), 'sub', ...);

Laravelのdocsに私のプルリクが通った

これはビッグニュースですね!

OSS活動もっとやりたかったですが、結局今年はこれだけになるかも...

github.com

2018年5月のLaravel

Laravel 5.6.20→24

abort()の引数にresponseを設定でHttpResponseExceptionを返すようになった

 ②EloquentにloadMissing()メソッドが追加されました

リレーションがloadingしてない時だけloadingしてくれます。

public function format(Book $book)
{
    $book->loadMissing('author');

    return [
        'name' => $book->name,
        'author' => $book->author->name
    ];
}

2018年6月のLaravel

Laravel 5.6.25→26

①query builderにjson形式のデータに対するメソッドが追加されました

whereJsonNotContains()orWhereJsonNotContains()、が追加されました。

含まれない条件のandとorですね。

$query->whereJsonNotContains('options->languages', ['en']);
$query->orWhereJsonNotContains('options->languages', ['en']);
②ModelにunsetRelation()メソッドが追加されました

メソッド名通り、リレーションをunsetしてくれます。

③AuthにhasUser()メソッドが追加されました

動作的にはAuth::guard()->user()をパブリックに使えるようにしたものです。

github.com

 Laravel Event

Laravelのイベントを告知するサイトが出来ました。

世界中のイベントが載っています。

Laravel Events

 

Laravel Live UK

UKでカンファレンスが開催されました。

世界中で開催されていますね。

laravellive.uk

 

2018年7月のLaravel

Laracon US 2018

今年のLaracon USはシカゴで開催されました!

Laraconのサイトは2019仕様に既に変わってしまいましたが

2018年のセッションはYoutubeに再生リストで上がっており見ることが出来ます。

(Vue.jsのEvan氏もセッションに参加しております。)

www.youtube.com

 

私は開催当日、日本で早朝からtwitterと動画配信を追いかけてましたが、

クラシコムのエンジニアの方がLaracon US参加レポートを書かれています。

日本人の参加者がほとんどいないため、会場の雰囲気など大変参考になります!

note.mu

Laravel Nova発表

Laravel Novaは公式のLaravel管理画面作成用パッケージになります。

サイト単位の有料ライセンスパッケージになっており、サポート付きかそうでないかで

料金が違います。

詳細は以下のページで確認できます。

Laravel Nova - Beautifully-designed administration panel for Laravel

 

弊社でも8月にリリースしたGraspyというサービスで早急に管理画面が必要になったため、発売開始直後にサポート付きライセンスを購入致しました。

そこでの知見はまたこのブログで展開できればと思います!

graspy.jp

2018年8月のLaravel

Laravel 5.6.30→34

セキュリティパッチのリリースがありました

Laravel 5.6.30とLaravel 5.5.42がセキュリティ対策版のリリースバージョンになります。

laravel-news.com

Laravel EU 2018開催

laracon.eu

2018年9月のLaravel

Laravel 5.7 Release

ディレクトリ構成の変更

こちらが5.6までの構成です。

/resources
├── assets
│   ├── js
│   └── sass
├── lang
│   └── en
└── views

以下が新しいディレクトリ構成になります。集約されました。

/resources
├── js
├── lang
├── sass
└── views
②エラーメッセージがわかりやすくなりました

これメッチャ良いですね。Laravelのエラーメッセージはプログラミング初心者等には

かなり厳しい感じはしていました。

③ページネーションの中央のリンクに対するサイドの数を設定出来るようになりました。

デフォルトは3になります。

// [1][2][3]...[6][7][8]【10】[11][12][13]...[20][21][22]
User::paginate(10)

// [1][2][3]...[9]【10】[11]...[20][21][22]
User::paginate(10)->onEachSide(
1);
④Mail Localizationが簡単に出来るようになりました
  • Mail::to($user)->locale('en')->send(new OrderConfirmation($order))
  • Mail::to($user)->locale('ja')->send(new OrderConfirmation($order))

Laravel meetup Tokyo Vol.11開催

2回目の参加になりました!

発売前のLaravel本の紹介などもあり、とても充実した内容でした。

laravel-meetup-tokyo.connpass.com

Laravel本「PHPフレームワーク Laravel Webアプリケーション開発 」発売

これまでに無かった一つレベルの上がった中級者以上向けの本になるかと思います。

実践パターンが豊富で、非常に参考になる1冊でした。

www.amazon.co.jp

2018年10月のLaravel

Laravel 5.7.9→5.7.12

CollectionにloadCount()が追加されました

withCount()は元々あったのですが、loadでリレーションする際にはメソッドが用意されていなかったのが今回追加されました。

$events = Event::latest()->with('eventable')->paginate();

$groups = $events->map(function ($event) {
    return $event->eventable;
})->groupBy(function ($eventable) {
    return get_class($eventable);
});

$groups[Post::class]->loadCount('comments');
$groups[Comment::class]->loadCount('hearts');

return new EventIndexResponse($events); 

Laravel Telescope発表

Laravel Telescopeは新しいLaravelのデバッグ用アプリです。

わかりやすいGUIを兼ね備えており、Laravelの処理全般を確認することが出来ます。

mattstauffer.com

Laravel AU 2018

オーストラリアでのカンファレンスが開催されました。

これに伴い、Laravelの作者のTaylor Otwellが日本に来日して

観光を楽しんでいたようです。

laracon.com.au

 

 

 

2018年11月のLaravel

Laravel 5.7.13

CollectionにwhenEmpty()whenNotEmpty()unlessEmpty()unlessNotEmpty()メソッドが追加されました

whenEmpty()の処理はコレクションが空の時にコールバックが呼ばれます。

$collection = new Collection;

$collection->whenEmpty(function ($collection) {
    return $collection->push('test');
});

$this->assertSame(['test'], $collection->toArray());

unlessEmpty()の処理はコレクションが空でない時にコールバックが呼ばれます。

$collection = new Collection;

$collection->unlessEmpty(function ($collection) {
    return $collection->push('abcd');
});

$this->assertSame([], $collection->toArray());

2018年12月のLaravel

Laravel Advent Calendar

12月といえば、Advent Calendarですね!

今年は#2まで出来ております。

私は今年初参戦ですが何か役に立つ記事を書ければと思います!

qiita.com

qiita.com

2019年のLaravel

Laravel JP Conference

来年2月に、日本初のLaravelカンファレンスが開催されます!

ララベラー全員集合間違いなしですね。

conference2019.laravel.jp

Laracon VII (Laracon US 2019)

来年のLaracon US 2019の開催は既に発表されております!

今年はシカゴでしたが来年はNYです!行きたい!

Laravel 5.8

5.8の話も少しずつ出てきていますね。

①Carbon2を使えるようになる

ついにCarbonのv2を選べるようになることで、immutableに扱えるようになります!

(既にmutableな使い方に慣れてしまっていますが...)

laravel-news.com

②Laravel mixも進化するみたい

テスト中にLaravel Mixをオーバーライドすることが出来るみたいです!

timacdonald.me

該当のPRはこちらです。

github.com

Laravel 6 ?

Laravel 6やLaravelの今後を知るには、Laravelのアイディアを纏めた以下のリポジトリのissuesを読むのが一番だと思います。

github.com

以前はLaravel6のwishlistも有りましたが、今は閉じられています。

github.com 

Laravelは5系の完成度が高く、LTSもあるためか、メジャーバージョンのアップデートサイクルが当初の想定よりずれています。(特に悪いことではないと思います) 

Laravel4→5で実施したようなチャレンジングな進化を6にも期待したいですね。

 

長くなりましたが今年のLaravelをまとめてみました。 

こうしてみると色んな事があった盛り沢山な1年だったと思います。

来年もLaravelの勢いが続くように少しでも貢献できればと思います。

最後に

ITプロパートナーズでは大半のサービスのサーバーサイド開発をLaravelを利用して行っています。

この記事を最後まで読んだそこのあなたは相当なララベラーだと思います!

一緒にLaravelやりませんか?

もし興味があれば気軽にオフィスに遊びに来てください!

 

www.wantedly.com

 

www.wantedly.com