こんにちは! ITプロパートナーズ(https://itpropartners.jp/)インターンの栗岡です!
普段は、Laravelで自社サービスの開発をしたり、新卒採用関係の業務をやっています。
今回は、1月12日に弊社渋谷オフィスで開催されたもくもく会をレポートします!
続きを読むこんにちは! ITプロパートナーズ(https://itpropartners.jp/)インターンの栗岡です!
普段は、Laravelで自社サービスの開発をしたり、新卒採用関係の業務をやっています。
今回は、1月12日に弊社渋谷オフィスで開催されたもくもく会をレポートします!
続きを読むこんにちは。
ITプロパートナーズでエンジニアの米川(@keiuwk0614)です。
普段は、自社プロダクトである中途向けの転職サービスGraspy(https://graspy.jp/)の開発をしています。フロントエンドはNuxt.js、サーバサイドはLaravelを使用し開発しています。
今回は、初学者向けにNuxtのプロジェクト作成から、外部APIを呼び出して簡単なWebアプリケーションを開発し、Firebaseのホスティングにデプロイするまでを紹介していきたいと思います。
プロジェクトを作成するディレクトリに移動し、公式ドキュメント(インストール - 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
選択後、全ての依存関係がインストールされプロジェクトが作成されます。
作成したプロジェクトのディレクトリに移動し、下記コマンドを実行します。
$ yarn run dev
デフォルトで3000番ポートが開きます。 http://localhost:3000 でアクセスし下記画面が表示されれば成功です。
デフォルトのポート番号を変更したい場合は、package.jsonのdevの引数にポートを指定するか、
"scripts": {
"dev": "nuxt --port 3333",
}
nuxt.confing.js内に設定することで変更できます。
module.exports = {
server: {
port: 8888,
},
// その他設定
}
今回使用するのは、GET /api/v2/items という記事の一覧を作成日時の降順で返却するAPIを使用します。詳細は下記の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/itemsのAPIには次のパラメータが設定できます。
今回は、10件のデータを取得してくるように固定で設定します。
何かキーワード検索したい場合は、queryというパラメータに検索したいキーワードを設定することも可能です。
params: {
page: 1,
per_page: 10,
query: 'Nuxt.js',
}
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>
ブラウザに戻り、上記コードコピペしていれば次のような画面が表示されていると思います。
これで一旦、Qiita APIを呼び出し記事の一覧を表示するところまでは完了になります。
コンポーネントの切り出し、デザイン等は各自でカスタマイズして貰えればと思います。
Firebase Console(https://console.firebase.google.com/?hl=ja)にアクセスし、googleアカウントでログインします。
プロジェクト、ロケーションの設定、規約に同意しプロジェクトを作成を押下します。
自動でFirebaseの管理画面に遷移します。
先ほど作成したプロジェクトのディレクトリで、Firebase CLIをインストールしFirebaseコマンドを使用できるようにします。
$ yarn global add firebase-tools
下記のコマンドを実行し、firebaseにログインします。
このコマンドを実行するとローカルコンピュータがFirebaseアカウントに接続され、プロジェクトへのアクセス権が付与されます。
$ firebase login
下記コマンドを実行し、ホスティングの初期設定を行います。
$ 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というファイルが自動で作られます。
下記コマンドを実行します。
dist/
配下に静的ファイルが生成されます。
$ yarn build
本番環境に公開します。
$ firebase deploy
無事にデプロイできましたでしょうか。
firebase Hostingのダッシュボードでデプロイが成功したか、デプロイ先のドメインが分かります。
筆者がデプロイしたものは下記のURLからご確認頂けます。
https://nuxt-tutorial-491c1.firebaseapp.com/
今回作成したコードは、githubに公開していますので全体を見たい人はこちらを参考にしてください。
GitHub - keiyonekawa0614/nuxt-firebase: nuxt + qiita API + firebase hosting sample
ちょっと応用してキーワード検索できるものも作ってみました。
こちらもgithubにソースコードを公開しておりますので、参考にしてみてください。
GitHub - keiyonekawa0614/nuxt-tutorial: Web service to search qiita articles.
ITプロパートナーズでは、Laravel、vue.js、Nuxt.jsで開発に挑戦したいエンジニア・デザイナーを絶賛募集中です。少しでも興味のある方は、DMでもGraspy、Wantedlyでもお気軽にご連絡頂けますと嬉しいです。お待ちしております。
ITプロパートナーズの新卒採用サービス「intee」のエンジニアの五藤です。
inteeの技術スタックは、バックエンドがPHP(CakePHP3)、フロントエンドがVue.jsを採用しています。 ユーザーが見る画面はもちろんの事、弊社スタッフが利用する管理画面に関しても、新しく実装する画面に関してはほとんどVueを使って管理画面を構築しています。
「何で管理画面のフロントエンドをリッチにする必要が?」
って思われるかもしれませんが、管理オペレーションが複雑になってくると、
などなど、オペレーション最適化の面で、リッチなフロントエンドを提供するメリットは意外と多く、営業サイドから 「この画面をVueを使ってサクサク使えるようにしてほしい」 という要望を受けることもしばしばだったります。
そんな中で、UI/コンポーネントライブラリとして愛用しているのが、Element です!
Element - The world's most popular Vue UI framework
各種フォーム部品やモーダルやアラート、簡単なグラフ表示などの、リッチな画面を作るのに必要なコンポーネントが揃っているニクいやつです。しかも、Vueのコンポーネントとして実装されているため、
<el-tag type="success">Elementに用意されてるめっちゃきれいなタグUI</el-tag>
という感じに、HTMLライクな書き方で簡単にコンポーネントを配置できるのも嬉しいところです。
今回は、その中でも、管理画面の画面設計の中核を占める <el-table> の使い方や、実装上のポイントについてまとめます!
( element-ui公式 より引用 )
簡単に言うと、管理画面でよくある、「データ一覧をテーブル形式で表示する」事ができるコンポーネントです。 これだけ書くと凄くシンプルなので、elementの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に設定された全カラムが勝手に出力されるのではなく、コンポーネント側で出したい情報を自由にピックできる のがポイントで、実際の想定シーンとしては、
というやり方で、 汎用的なAjaxの戻り値を、そのまま<el-table>にぶちこめる のが実装上は凄く楽だったりします。
各カラムに表示する値は、HTML形式で動的に設定可能で、更に言うと、他のelementのコンポーネントを配置することも出来ます。
[いろんなタグを配置してみるとこんな感じ]
こんな感じで、画像やアイコン、タグ、ボタンなどを各カラムにポチポチ配置して、可読性の高い画面をデザイナー抜きで簡単に作ることが出来ちゃいます。 もちろんボタンに導線を作ることもできるので、
といった処理を組むことも簡単です。 ちなみにモーダルもelementで用意されています。
http://element.eleme.io/#/en-US/component/dialog
いたれりつくせりですね。
・・・どうですか?管理画面に<el-table>使いたくなりませんか?
<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 }) },
いくつかポイントを上げると、
という感じです。
表示カラムは<el-table-column> を使うといいましたが、2つの記法があります。
<el-table-column prop="full_name" label="氏名"> </el-table-column>
propプロパティに直接Objectのキーを指定すると、文字列としてデータが表示されます。
もう少しリッチに各カラムのデータを書きたい場合は、このように書きます。
<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.$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>
はページングのための特別な仕組みを持たないため、
<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側で、
を共通化して持っておくと、このパターンのテーブル表示を量産する上では役に立ちます。 こんな感じでしょうか。
// 管理画面の汎用テーブルプラグイン 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> をご活用ください!
こんにちは! ITプロパートナーズ(https://itpropartners.jp/)インターンの栗岡です!
普段は、Laravelで自社サービスの開発をしたり、新卒採用関係の業務をやっています。
今回は、11月25日に弊社渋谷オフィスで開催されたもくもく会をレポートします!
続きを読むさなぽんです。社内ではマッチングサービスを中心とした受託案件のお仕事をしています。
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』を行います。
観覧者を大募集していますので、興味のある方は是非お越しください!
12月18日(火)にSIerやSESからWEBエンジニアへのキャリアチェンジをテーマにしたイベントを開催します。
ワタクシが司会をする予定です。こちらもよろしくお願いします。
こんにちは。エンジニアのとみ(@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はpug、cssはsassを使いました。
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 ''
さらにimport、fromで外部のjsファイルから項目内容を読み込むことができます。
import { genderLabels } from '~/enums/enums.js'
importしたjsはこのような中身。
・vuelidate
vue.jsプラグインのvuelidate(https://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で開発に挑戦したいエンジニア・デザイナーを絶賛募集中です!
12月ではSIerやSESからWEBエンジニアへのキャリアチェンジをテーマにしたイベントも開催します!
採用以外でも、様々なイベントを開催予定です!もくもく会、キャリアを考える会、フリーランスの方のコミュニティ会、12月には新サービス「Graspy」のプレミア勉強会(講師陣がめちゃくちゃ豪華です!)など...ご興味のあるイベントがあれば、ぜひオフィスに遊びに来てください😄
こんにちわ、ITプロパートナーズのエンジニアのくまモンエンジニア(@miyakey7)です。
Laravel駆動転職(LDJC)により今年1月にITプロパートナーズにジョインしました。
初めて実務でLaravelを使った開発を行い、あっという間に11月になってしまいました。
そうですね、気になりますよね?
2018年、Laravelにはどんな変化があったのか気になりますよね?
今回は少し早いですが2018年のLaravelに関する出来事や気になる変更点などを自分なりにピックアップして書きます!
(11月以降は随時追記していきたいと思いますw)
このメソッドは引数で指定したカラム名をモデルのテーブルで修飾します。
// 元々の記述
$this->getTable().'.'.$this->getKeyName();
// qualifyColumnを使った記法
$this->qualifyColumn($this->getKeyName()) ;
// 使用例
$article->qualifyColumn('title'); // -> articles.title
使った事無いという方、Eloquent内でしっかり動いております!
気になる方は以下を確認ください!
そうですねexists()はよく使うのですが5.5.33より、doesntExists()が追加されております!
ちなみに一瞬notExists()という名前になりそうでした。
if( !User::where('email', 'user@example.com')->exists() ){
}
↓
if( User::where('email', 'user@example.com')->doesntExists(){
}
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(); }
「Laracon Online 2018」が開催されました!
Laravelのオンラインカンファレンスは毎年開催されています!
今年の目玉はやはり、Laravel 5.6のリリースでした!
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',
],
],
$castsを定義することで取得時指定したデータ形式にキャストされます。
protected $casts = [
'birthday' => '誕生日:Y-m-d',
'logined_at' => 'datetime:Y-m-d H:00',
];
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
時代は4ですね。
使い方は以下にまとめてあります!
4桁数字認証を簡単に実装できるパッケージが公開されました。
5.6以降から使えます。
使い方は以下にまとめてあります!
以下の書き方で利用できます。
$query->where('name', 'sounds like', 'John Doe');
元々あった@ddとの違いは、処理が止まらないことですね。
Coming in next release of Laravel 5.6… easily attach files from Storage (S3, etc.) to mailables! 🔥 Thanks @reinink for the inspiration. pic.twitter.com/gRaLDivnNJ
— Taylor Otwell 🏄♂️ (@taylorotwell) March 7, 2018
orWhereDay()、orWhereMonth()、orWhereYear()が追加されました。
\App\User::whereDay('updated_at', '=', 1)
->orWhereDay('updated_at', '=', 2);
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が対策版のバージョンになります。
10回目で初参加しました。とても勉強になりモチベーションが上がる楽しいmeetupです。
laravel-meetup-tokyo.connpass.com
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', ...);
これはビッグニュースですね!
OSS活動もっとやりたかったですが、結局今年はこれだけになるかも...
Added support for passing any response (or Responsable) to "abort" helper... can be useful. ✌️ pic.twitter.com/9kV1kqA4uc
— Taylor Otwell 🏄♂️ (@taylorotwell) April 30, 2018
リレーションがloadingしてない時だけloadingしてくれます。
public function format(Book $book)
{
$book->loadMissing('author');
return [
'name' => $book->name,
'author' => $book->author->name
];
}
whereJsonNotContains()、orWhereJsonNotContains()、が追加されました。
含まれない条件のandとorですね。
$query->whereJsonNotContains('options->languages', ['en']);
$query->orWhereJsonNotContains('options->languages', ['en']);
メソッド名通り、リレーションをunsetしてくれます。
動作的にはAuth::guard()->user()をパブリックに使えるようにしたものです。
Laravelのイベントを告知するサイトが出来ました。
世界中のイベントが載っています。
UKでカンファレンスが開催されました。
世界中で開催されていますね。
今年のLaracon USはシカゴで開催されました!
Laraconのサイトは2019仕様に既に変わってしまいましたが
2018年のセッションはYoutubeに再生リストで上がっており見ることが出来ます。
(Vue.jsのEvan氏もセッションに参加しております。)
私は開催当日、日本で早朝からtwitterと動画配信を追いかけてましたが、
クラシコムのエンジニアの方がLaracon US参加レポートを書かれています。
日本人の参加者がほとんどいないため、会場の雰囲気など大変参考になります!
Laravel Novaは公式のLaravel管理画面作成用パッケージになります。
サイト単位の有料ライセンスパッケージになっており、サポート付きかそうでないかで
料金が違います。
詳細は以下のページで確認できます。
Laravel Nova - Beautifully-designed administration panel for Laravel
弊社でも8月にリリースしたGraspyというサービスで早急に管理画面が必要になったため、発売開始直後にサポート付きライセンスを購入致しました。
そこでの知見はまたこのブログで展開できればと思います!
Laravel 5.6.30とLaravel 5.5.42がセキュリティ対策版のリリースバージョンになります。
こちらが5.6までの構成です。
/resources
├── assets
│ ├── js
│ └── sass
├── lang
│ └── en
└── views
以下が新しいディレクトリ構成になります。集約されました。
/resources
├── js
├── lang
├── sass
└── views
これメッチャ良いですね。Laravelのエラーメッセージはプログラミング初心者等には
かなり厳しい感じはしていました。
Ever mistyped a method on an Eloquent model and got a cryptic error saying that the method doesn't exist *on the query builder* 😳
— Joseph Silber (@joseph_silber) August 12, 2018
Well, in @laravelphp 5.7 you'll now get a clear, concise message saying that the method doesn't exist on the model 👌https://t.co/uKAxbIVdmv pic.twitter.com/aWgQ8zr2ak
デフォルトは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::to($user)->locale('en')->send(new OrderConfirmation($order))
Mail::to($user)->locale('ja')->send(new OrderConfirmation($order))
2回目の参加になりました!
発売前のLaravel本の紹介などもあり、とても充実した内容でした。
laravel-meetup-tokyo.connpass.com
これまでに無かった一つレベルの上がった中級者以上向けの本になるかと思います。
実践パターンが豊富で、非常に参考になる1冊でした。
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のデバッグ用アプリです。
わかりやすいGUIを兼ね備えており、Laravelの処理全般を確認することが出来ます。
オーストラリアでのカンファレンスが開催されました。
これに伴い、Laravelの作者のTaylor Otwellが日本に来日して
観光を楽しんでいたようです。
— Taylor Otwell 🏄♂️ (@taylorotwell) October 14, 2018
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());
12月といえば、Advent Calendarですね!
今年は#2まで出来ております。
私は今年初参戦ですが何か役に立つ記事を書ければと思います!
来年2月に、日本初のLaravelカンファレンスが開催されます!
ララベラー全員集合間違いなしですね。
来年のLaracon US 2019の開催は既に発表されております!
今年はシカゴでしたが来年はNYです!行きたい!
Laracon VII! July 24-25, 2019 at the PlayStation Theater in Times Square, NYC! 🔥https://t.co/Txd9CgMCfC
— Laravel (@laravelphp) November 13, 2018
5.8の話も少しずつ出てきていますね。
ついにCarbonのv2を選べるようになることで、immutableに扱えるようになります!
(既にmutableな使い方に慣れてしまっていますが...)
テスト中にLaravel Mixをオーバーライドすることが出来るみたいです!
該当のPRはこちらです。
Laravel 6やLaravelの今後を知るには、Laravelのアイディアを纏めた以下のリポジトリのissuesを読むのが一番だと思います。
以前はLaravel6のwishlistも有りましたが、今は閉じられています。
Laravelは5系の完成度が高く、LTSもあるためか、メジャーバージョンのアップデートサイクルが当初の想定よりずれています。(特に悪いことではないと思います)
Laravel4→5で実施したようなチャレンジングな進化を6にも期待したいですね。
長くなりましたが今年のLaravelをまとめてみました。
こうしてみると色んな事があった盛り沢山な1年だったと思います。
来年もLaravelの勢いが続くように少しでも貢献できればと思います。
ITプロパートナーズでは大半のサービスのサーバーサイド開発をLaravelを利用して行っています。
この記事を最後まで読んだそこのあなたは相当なララベラーだと思います!
一緒にLaravelやりませんか?
もし興味があれば気軽にオフィスに遊びに来てください!