- 投稿日:2020-09-21T22:15:09+09:00
初学者チームがWebサービス開発を始めて4週間で出来たことと出来なかったこと
2週間前にアップした「初学者チームがWebサービス開発を始めて最初の2週間でやったことを振り返り、そして次を考える」という記事から、また2週間経ったので、どこまで進捗したのかまとめたいと思います。
「初心者だけど何かモノを作ってみたい!」という方の参考になれば幸いです。
目標達成度
2週間前掲げていた目標と、実際できたことを整理します。
こちらが2週間前の記事では言っていたこと。というわけで、次なる目標ですが、深い意味は特になく、なんとなくまた2週間先(9/21月曜)にチェックポイントを置きたいと思います。
目標は、9/21Monまでに人にURLをばら撒けるレベルのサイトにしたい!です。
具体的には、下記8点の要件を満たしたいです。その8点と結果がこちら。
2週間前掲げた目標 達成度 10点満点 コメント Heroku上でアプリが機能する 8 2週間前はHerokuにデプロイしたてでエラーもしばしば。今は表示は安定、基本動作も問題なし。 ページ内のリンクなど、ページがきちんと遷移する 5 まだ作れてないページがあったり、戻るボタン、キャンセルボタンなどが欠けています。 シンプルだが見るに耐えうるデザインであり全ページに統一感がある 3 フロントチームは頑張って作ってくれたのですが、サーバーサイドがそこまで手が回りませんでした。 投稿が新着順で表示でき、1ページの投稿は10件まで、それ以上は別ページとする 9 今ではペジネーションという専門用語も覚えました!でもデザイン配置のカスタマイズができてないので-1。 投稿がキーワード検索できる 0 全く手をつけてませんでした涙 アカウント登録した人がログイン、ログアウト、投稿、削除、編集できる 9 Laravelデフォルトのユーザ認証機能も利用しつつ、自分らのデザインを当て込むこともできてきました。 ゲストでも投稿できる 10 できました。 Contactページから問い合わせすると運営にメールが届く 5 今日滑り込みでメールを受信するまでの基礎機能の実装はできました。 総合得点 49/80 達成度61% 60点ならまずまずではないでしょうか!ただ、残念ながらまだ胸を張ってURLを配れるようなレベルはなりませんでした。
そして、ストレッチで掲げていた目標は綺麗に一切手を付けられませんでした(笑)↓
ストレッチ目標 達成度 10点満点 コメント アカウントがアイコン画像を設定できる 0 投稿に画像を1枚添付できる 0 ミュージシャンごとの投稿を集約したページが生成できる 0 ライブハウスごとの投稿を集約したページが生成できる 0 いいね!ができる 0 利用規約のページがある 0 管理人が不適切な投稿を削除できる 0 総合得点 0/70 達成度0% その他にこの2週間でできたこと箇条書き↓
- DBの再設計
- 全ページのHTML/CSS作成完了、ブラッシュアップ(コードの視認性、Font Awesome使用)
- ログイン認証
- HerokuのアドオンDB(ClearDB MySQL)を設定
- MySQLの文字コード設定で日本語の文字化け解消
- MySQLのタイムゾーン変更
- 投稿にタグを付ける初期機能実装
感想3つ
(そういうのいいよって方は飛ばしてください)
初心者なのにモノを作ってみた感想
人それぞれ勉強方法はあるのかもしれませんが、基礎から教科書をやっていくという勉強方法よりも、実際にモノを作るというこの方法が僕には一番合っていると感じています。めっちゃくちゃ夢中になっています。ただし!1ページめくれば、次の手順を教えてくれるテキスト学習と違って、1歩進むごとに、何をしたらいいのかわからない、どう調べればいいかもわからない、手をつけたらエラーになるの繰り返しです。
上手くいかない時は、焦るし、焦って変なコマンド打ってしまったり、イライラしたり、精神的に安定しないこともありました。一般人は「プログラミングは超絶簡単」「1ヶ月でできるようになる」という有名人の言葉を鵜呑みにしない方がいいです。でも何かちょっと対策を講じてエラー文章が変わり、それで推理が進んで、原因を突き止めて、前に進んだ時の喜びと快感は尋常じゃなかったりします。
仲間という存在の貴重さ
まこなり社長さんが「プログラミング学習には仲間を作った方がいい」と仰っているのを聞いたことがありますが、僕も同意です。あれは単なるテックキャンプへ誘導する文言ではないと思います(笑)僕の理由は「行き詰まった時、話せる相手がいるのは超助かるから」です。相談する相手も初学者なので、答えがもらえるとは限らないのですが、一緒に調べてくれたり、解決のヒントを与えてくれたりします。自分の思考がクリアになって、話してるうちに閃くということも経験しました。そして何より精神的に落ち着けます。こういうことで悩んでるんだよねーというと、「わかるーー!」と言ってもらえるだけでなんか落ち着けるんですよね。女子の気持ちが少しわかりました(笑)
ただし、初心者のチーム開発はハッキリ言って楽ではありません。でもその大変さを差し引いてもプラスになっていると思います。
あと先輩やメンターの存在も結構大きいです。それらが揃ってるYouTube万屋エンジニアチャンネル超おすすめっす!
開発初期にはプログラミング以外の時間が結構かかる
最初の3週間はアプリの企画、設計を考えたり、開発環境を整えたりで手一杯で、コードを書く状態に至りませんでした。(フロントチームはその間HTML/CSSでサイトの見た目を作ってくれていました)ようやく4週間めくらいからプログラムを書けるようになってきて、やっぱりコーディングの方が楽しいなと思いました。
今後の開発
次の目標
期限:10/5月曜18:00
下記10点の実装を目指します。
- 継承レイアウトで構築し、サイト全体にデザインの統一感がある
- 投稿の文章が長い場合、全文表示/一部表示の切り替えができる
- ドロップダウンメニュー
- 投稿の際、チップスの効いたタグ付けができる
- 投稿に付いたタグをクリックするとそのタグの投稿一覧を表示できる
- 登録ユーザーの投稿一覧が表示できる
- 検索機能
- いいね機能の実装
- Contactから運営側にメールが届き、問い合わせ内容がわかる
- ユーザーがプロフ画像を設定できる
開発体制の変更
今まではフロントには一旦別環境でHTML/CSS作りに集中してもらっていたのですが、開発が進んできてそれでは大変になってきそうなので、フロントチームもLaravelを入れてもらってバックエンドと同じ環境下でフロントのブラッシュアップをしてもらうつもりです。
- 投稿日:2020-09-21T22:07:51+09:00
Laravel(mysql)
PHP拡張ツールをインストール
sudo apt-get install php-intlPDO関連のドライバーやその他のパッケージをインストールする
sudo apt-get install apache2 php php-gd mysql-server php-mysql php-zip sudo apt-get install php-mbstring php-xml php-json php-zip php7.4-cli もしくは sudo apt-get install php-mbstring php-xml php-json php-zip php7.2-cliapache2関連の設定
sudo apt-get install libapache2-mod-php sudo apt-get install apache2 sudo systemctl enable apache2 sudo systemctl restart apache2Mysqlのパスワードの設定。
※不要であれば飛ばしてOKsudo mysql_secure_installationPDO関連のドライバー(sqlite)を入れておく
sudo apt-get install php7.2-sqlite3 sudo apt-get install php7.4-sqlite3curlを入れておく
sudo apt-get install curlcomposerを入れておこう!!
curl -sS https://getcomposer.org/installer sudo apt-get install composer which composerパス設定の場所を変えよう(mv)でね
sudo mv composer /usr/local/bin/composer which composer所有権の設定を変えよう
sudo chmod 755 /usr/local/bin/composer export PATH=/usr/local/bin:$PATH which composerLaravel自体のインストールとかパスとか色々
composer global require "laravel/installer" export PATH="$PATH:/.config/composer/vendor/bin" source ~/.bashrcインストールからコレクティブの設定まで
composer create-project --prefer-dist laravel/laravel Laravelapp cd Laravelapp composer update composer install php artisan --version composer require "laravelcollective/html":"^8.4.0" composer require "laravelcollective/html":"^7.2.0" composer require "laravelcollective/html":"^6.2.0"sudo mysql -u root -p create database databasename; 下記でブラウザツールも併せて作っておくと楽になります。https://qiita.com/yuuki-furue/items/e2cb13b378f996fc69d9
下記は速攻で管理画面を作るコマンドです。因みに下記を入力することでVUE.JSをフロントエンドで使用できます。※好みですが・・・ composer require laravel/ui php artisan ui vue --auth sudo npm install sudo npm run dev
- 投稿日:2020-09-21T14:01:00+09:00
[Laravel]Laravel6.8 × Vue.jsでSPAを構築する流れ
今回の題
1ヶ月前に勉強がてらLaravelとVue.jsでSPAを構築してみたのですが、1ヶ月経った今、その手順をすっかり忘れてしまいました。
必要な時に振り返ればいい知識だとは思うのですが、忘れすぎて少し癪だったのでアウトプットしておきます。この記事では、HomeとUserというページを作り、それぞれをページ遷移を行わずに切替えられる様にします。
ページのコンテンツとURLがページ遷移なしに切り替わっているのがわかると思います。
バージョン
- Laravel6.8
- Laravel Mix 4.1.4
- Vue.js 2.6.12
- Vue Router 3.4.3
手順
Laravelのインストール
$ composer create-project "laravel/laravel=6.8" laravel-spa各種パッケージのインストール
- Vue.js
$ npm install vue --save-dev
- Laravel Mix
$ npm install laravel-mix --save-dev
- Vue Router
$ npm install vue-router --save-dev
- cross-env
$ npm install cross-env --save-devLaravel Mixの設定
webpack.mix.js
にコンパイル先を定義します。webpack.mix.jsconst mix = require('laravel-mix'); mix.js('resources/js/app.js', 'public/js') .version();これで
resources/js/app.js
に書いたVueはpublic/js
にコンパイルされます。
version()はキャッシュ対策です。
ブラウザに以前のJavaScriptがキャッシュとして残っていると、キャッシュの方を使ってしまうので、ここでversion()を使い、さらにviewでmix関数を使ってjsを読み込むことで対策出来ます。
参考コンパイル
以下のコマンドで変更を監視し、自動的にコンパイルが行われる様にします。
$ npm run watch各種ファイル作成
view
resources/views/index.blade.php<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <div id="app"> <router-view /> </div> <script src="{{ mix('js/app.js') }}"></script> </body> </html>router.js
resources/js/
にrouter.jsを作成。
SPAのルーティングはここに定義します。router.jsimport Vue from 'vue' import Router from 'vue-router' import Home from './components/pages/Home' import User from './components/pages/User' Vue.use(Router) export default new Router({ mode: 'history', routes: [ { path: '/', name: 'home', component: Home }, { path: '/user', name: 'user', component: User }, ] })Vue.jsとvue-router、使用するコンポーネントをimportしたあと、ルーティングでパスにコンポーネントを割り振っています。
参考app.js
resources/js/app.js
を以下の様に編集します。import Vue from 'vue' import router from './router.js' new Vue({ router }).$mount('#app')Vue.jsとvue-routerをimportして、routerを適用する要素を設定します。
コンポーネント
ページの内容となるコンポーネントは
components
ディレクトリで管理します。$ mkdir resources/js/components
components
ディレクトリにpages
ディレクトリを作成し、$ mkdir resources/js/components/pagesそこに、
Home.vue
User.vue
というファイルを作り、以下の様にそれぞれ編集します。Home.vue<template> <div> <h1>Home</h1> <router-link :to="{ name: 'user' }">User</router-link> </div> </template>User.vue<template> <div> <h1>User</h1> <router-link :to="{ name: 'home' }">Home</router-link> </div> </template>確認
以下のコマンドでビルトインサーバーを立ち上げ、
$ php artisan servehttp://127.0.0.1:8000/
にアクセスして確認してください。最初のgifの様な動きが確認できるはずです。
あとはこれを土台に好きな様に弄り回してSPAで色々作れると思います。以上!!
一言
最初SPAの構築ができた時、めちゃくちゃ興奮して無駄にページ行き来しまくりました。
SPAすごい技術だなぁ……。参考
readouble アセットのコンパイル
Vue Router
Laravel6.xとVue Routerでvue.jsのSPA構築
- 投稿日:2020-09-21T13:48:10+09:00
Heroku(Laravel)で自作アプリをHerokuにデプロイしようとしたらマイグレーションエラーが起きたので、ClearDB(MySQL5.5)からJawsDB(MySQL8.0)に変更した時の備忘録
開発環境
PHP7.3
Laravel5.8
MySQL8.0
Heroku使用時のDBアドオン:ClearDB MySQL5.5やろうとしたこと
下記をheroku run php artisan migrate
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Query\Expression; use Illuminate\Support\Facades\Schema; class CreateChatRoomsTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('chat_rooms', function (Blueprint $table) { $table->id(); $table->text('user_info_json')->default(new Expression('(JSON_ARRAY())')); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('chat_rooms'); } }エラーが出現。
エラーの内容
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(JSON_ARRAY()), `created_at` timestamp null, `updated_at` timestamp null) defaul' at line 1 (SQL: create table `chat_rooms` (`id` bigint unsigned not null auto_increment primary key, `user_info_json` text not null default ( JSON_ARRAY()), `created_at` timestamp null, `updated_at` timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci')SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(JSON_ARRAY()), `created_at` timestamp null, `updated_at` timestamp null) defaul' at line 1推測
$table->text('user_info_json')->default(new Expression('(JSON_ARRAY())'));の部分がSQLのバージョンに対応していないらしい。
ローカル(MySQL8.0)ではエラーは起こらなかったため、本番環境のSQLをバージョンアップすれば通るかも?
ClearDBからJawsDBにアドオンを変更しよう
ClearDB・・・MySQL5.5、5.6、5.7対応
JawsDB・・・5.7及び8.0対応
とのことであったため、ローカル環境(MySQL8.0)と合わせるべくJawsDBにアドオンを変更することに。JawsDBアドオン取得
heroku addons:create jawsdb:[プラン名] -a [アプリ名] --version=8.0--version=8.0のようにすることで、バージョンを8.0指定でインストール。
ClearDBの環境変数を削除
JawsDBをインストールしただけの状態なので、まだClearDB使用時の環境変数が登録されている。
DB_DATABASE: [ClearDBのDATABASE] DB_HOST: [ClearDBのHOST] DB_PASSWORD: [ClearDBのPASSWORD] DB_USERNAME: [ClearDBのUSERNAME]これらを全て一旦削除
heroku config:unset DB_DATABASE heroku config:unset DB_HOST heroku config:unset DB_PASSWORD heroku config:unset DB_USERNAMEその後
heroku configすると、ClearDBの環境変数が消えている。
JawsDBの接続情報を確認
heroku config |grep JAWSDB_URL JAWSDB_URL: mysql://[DB_USERNAME]:[DB_PASSWORD]@[DB_HOST]/[DB_DATABASE]もしくはHerokuのマイページからJawsDBアドオンに遷移して確認。
JawsDBの環境変数登録
heroku config:set DB_DATABASE=[DB_DATABASE] heroku config:set DB_HOST=[DB_HOST] heroku config:set DB_PASSWORD=[DB_PASSWORD] heroku config:set DB_USERNAME=[DB_USERNAME]再度マイグレーション
heroku run php artisan migrate通った!
- 投稿日:2020-09-21T03:11:50+09:00
Laravel + Instagram Basic Display APIで投稿を取得する
はじめに
Laravelを触ってみながら、Instagram Basic Display API というAPIで自分のInstagramアカウントの投稿写真を 取得していこうと思います。
やること
- Instagram Basic Display APIに必要なアクセストークンを取得する
- Laravelで投稿を取得&表示する
- Laravelでアクセストークンを定期更新する
動作環境
- PHP 7.1.23
- Laravel 5.8
- MySQL 5.7
Instagram Basic Display APIとは
Instagram基本表示APIはHTTPベースのAPIです。アプリはこれを使用して、Instagramユーザーのプロフィール、画像、動画、アルバムを取得できます。
InstagramグラフAPIの簡易版で認証したユーザーに関する情報を取得できます。
InstagramグラフAPIと違って審査がいらないのでサクッと使いたい人向けです。できること
- ユーザのアクセス許可、アクセストークンの取得
- 発行したアクセストークンを使用して
- ユーザーのプロフィールを取得
- ユーザーの画像、動画、アルバムを取得
基本的に自分のアカウントの投稿をサイトに表示するなどの目的で使うのであればInstagram Basic Display APIで大丈夫だと思います。
前提
上記の公式のスタートガイドを参考にステップ3までを進めた状態で手順を進めていきます。
- ステップ1: Facebookアプリを作成する
- ステップ2: Instagram基本表示を構成する
- ステップ3: Instagramテストユーザーを追加する
ステップ4のテストユーザーを認証する~長期アクセストークンを取得するまでを書いていきます。
アクセストークンとアクセス許可を取得する
参考 : アクセストークンとアクセス許可を取得する
Instagram Basic Display APIを使うにはアクセストークンが必要になるので取得しましょう。
リクエスト例: ユーザーのプロフィールを取得する
GET /me?fields={fields}&access_token={access-token}認証を取得する
https://api.instagram.com/oauth/authorize ?client_id={instagram-app-id} &redirect_uri={redirect-uri} &scope=user_profile,user_media &response_type=code
instagram-app-id
[アプリダッシュボード] > [製品] > [Instagram] > [基本表示] で表示される InstagramアプリID
redirect-uri
[アプリダッシュボード] > [製品] > [Instagram] > [基本表示] で設定した クライアントOAuth設定の 有効なOAuthリダイレクトURL上記の内容を自分の設定に変えてアクセスします。
アクセス例https://api.instagram.com/oauth/authorize ?client_id=990602627938098 &redirect_uri=https://socialsizzle.herokuapp.com/auth/ &scope=user_profile,user_media &response_type=codeアクセスすると認証許可の画面が出てくるのでテスターとして登録したアカウントで許可しましょう
成功した場合のリダイレクト例
https://socialsizzle.herokuapp.com/auth/?code=AQBx-hBsH3...#_成功するとredirect_uriに設定したURL + ?code=AQBx-hBsH3...#_
こんな感じの文字列がURLのバーに表示されています。code= と #_ の間の文字列をこのあと使うので控えておきましょう。
この文字列をcodeといいこのあと使います。短命のアクセストークンを取得する
認証した際に取得した codeを用いて短命のアクセストークンを取得します。
POST https://api.instagram.com/oauth/access_tokenリクエストの例
curl -X POST \ https://api.instagram.com/oauth/access_token \ -F client_id={instagram-app-id} \ -F client_secret={instagram-app-secret} \ -F grant_type=authorization_code \ -F redirect_uri={redirect_uri} \ -F code={さっき取得したcode}
instagram-app-secret
[アプリダッシュボード] > [製品] > [Instagram] > [基本表示] で表示される Instagram App Secret成功した時の応答例
{ "access_token": "IGQVJ...", "user_id": 17841405793187218 }access_token ここの内容がAPIに必要なアクセストークンになります。
しかしこのままだとこのアクセストークンの使用できる期間は1時間と短命なので、長命のものと交換しましょう.
長期のアクセストークンを取得する
参考: 長期アクセストークン
curl -i -X GET "https://graph.instagram.com/access_token?grant_type=ig_exchange_token&client_secret={instagram-app-secret}&access_token={short-lived-access-token}"
short-lived-access-token
先ほど取得した access_token成功した時の応答例
{ "access_token":"{long-lived-user-access-token}", "token_type": "bearer", "expires_in":5183944 // トークンが有効期限切れになるまでの秒数 }
long-lived-user-access-token
が今回取得した長期トークンになります。しかし長期とは言ってもこれも
expires_in
に記載されている通り期限が存在します。
このトークンに関しては60日間有効なのですがそれをすぎると無効になってしまうため定期的にトークンを更新しないといけません。長期のアクセストークン更新する
参考: 長期アクセストークンの更新
最長でもアクセストークンは60日しか持たないので有効期限が切れる前に新しいアクセストークンと交換します。
リクエスト例
curl -i -X GET "https://graph.instagram.com/refresh_access_token?grant_type=ig_refresh_token&access_token={long-lived-access-token}"
long-lived-access-token
取得している長期アクセストークン有効期間が過ぎていない長期アクセストークンを指定してください
応答の例
{ "access_token":"{long-lived-user-access-token}", "token_type": "bearer", "expires_in":5183944 // トークンが有効期限切れになるまでの秒数 }
long-lived-user-access-token
が新たに取得した60日の有効期限の長期アクセストークンになります。ユーザーの投稿を取得する
参考: メディアデータを取得する
参考: pagingGET /me/media?fields={fields}&access_token={access-token}アクセス例
curl -X GET \ 'https://graph.instagram.com/me/media?fields=id,caption,permalink,media_url,thumbnail_url&access_token={access-token}'
access_token
は有効なアクセストークンを設定します。
fields
で取得するデータを選択できます。https://developers.facebook.com/docs/instagram-basic-display-api/reference/media#fields
応答例
{ "data": [ { "id": "メディアID", "caption": "キャプションテキスト", "permalink": "投稿先URL", "media_url": "画像URL" } ], "paging": { "cursors": { "after": "MTAxN...", "before": "NDMyN..." }, "next": "https://graph.faceb..." } }Laravel を利用する
プロジェクト作成
$ composer create-project --prefer-dist laravel/laravel instagram "5.8.*" $ cd instagramコントローラー作成
$ php artisan make:controller InstagramController
ルーティング追加
/routes/web.phpRoute::get('/instagram', 'InstagramController@index');token保存用の簡易的なテーブルを追加します
$ php artisan make:migration create_instagramTokens_table/database/migrations/...._create_instagram_tokens_table.php<?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateInstagramTokensTable extends Migration { /** * Run the migrations. * * @return void */ public function up() { Schema::create('instagram_tokens', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('access_token'); $table->string('token_type'); $table->integer('expires_in'); $table->timestamps(); }); } /** * Reverse the migrations. * * @return void */ public function down() { Schema::dropIfExists('instagram_tokens'); } }$ php artisan migrate
mysql> desc instagram_tokens -> ; +--------------+---------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +--------------+---------------------+------+-----+---------+----------------+ | id | bigint(20) unsigned | NO | PRI | NULL | auto_increment | | access_token | varchar(255) | NO | | NULL | | | token_type | varchar(255) | NO | | NULL | | | expires_in | int(11) | NO | | NULL | | | created_at | timestamp | YES | | NULL | | | updated_at | timestamp | YES | | NULL | | +--------------+---------------------+------+-----+---------+----------------+ 6 rows in set (0.00 sec)モデル作成
$ php artisan make:model InstagramToken
今回は最初の手順で有効な長期access_tokenを取得しているのでenvに追加しておきます。
/.envINSTAGRAM_TOKEN=取得した有効な長期アクセストークンLaravelでアクセストークンを更新
参考: Laravelのタスクスケジュール(cron)を使いこなす
Commandの作成
$ php artisan make:command Instagram
/app/Console/Commands/Instagram.php<?php namespace App\Console\Commands; use Illuminate\Console\Command; use App\InstagramToken; class Instagram extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'instagram:refresh'; /** * The console command description. * * @var string */ protected $description = 'Instagram access token update'; /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * * @return mixed */ public function handle() { // ここに処理を書いていく } }Commandの登録
/app/Console/Kernel.phpprotected $commands = [ Commands\Instagram::Class, ];トークンを更新する
/app/Console/Commands/Instagram.php/** * Execute the console command. * * @return mixed */ public function handle() { $baseUrl = "https://graph.instagram.com/refresh_access_token?"; // アクセストークン取得 $instagramToken = InstagramToken::select('access_token')->latest()->first(); $accessToken = env('INSTAGRAM_TOKEN'); if ($instagramToken->access_token) { $accessToken = $instagramToken->access_token; } // パラメーター設定 $params = array( 'grant_type' => 'ig_refresh_token', 'access_token' => $accessToken ); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $baseUrl . http_build_query($params)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $responseText = curl_exec($ch); $result = json_decode($responseText, true); curl_close($ch); // DB保存 if ($newAccessToken = $result['access_token']) { $instagramToken = new InstagramToken(); $instagramToken->access_token = $newAccessToken; $instagramToken->token_type = $result['token_type']; $instagramToken->expires_in = $result['expires_in']; $instagramToken->save(); } }実行してみる
$ php artisan instagram:refresh
mysql> select * from instagram_tokens; +----+-------------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+---------------------+---------------------+ | id | access_token | token_type | expires_in | created_at | updated_at | +----+-------------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+---------------------+---------------------+ | 1 | トークン | bearer | 5177185 | 2020-09-21 21:53:07 | 2020-09-21 21:53:07 | | 2 | トークン | bearer | 5177002 | 2020-09-21 21:56:10 | 2020-09-21 21:56:10 | | 3 | トークン | bearer | 5176998 | 2020-09-21 21:56:14 | 2020-09-21 21:56:14 | +----+-------------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+---------------------+---------------------+ 3 rows in set (0.00 sec)取得できていますね。
これを定期実行すれば有効期限問題は解消できそうです。参考: Laravelのタスクスケジュール(cron)を使いこなす
などを参考に有効期限の60日が来る前に定期的にトークンを更新するように設定しましょうscheduleの追加&cron設定
今回は
schedule
に追加する形で実装していこうと思います。
schedule
ではなくそのままphp artisan instagram:refresh
このコマンドをcron設定してもいいと思います。
schedule
にコマンドを追加することでcron設定を一個に済ませることができます
今回は実行するコマンドが一個なのであんまり恩恵はないかもしれませんが練習も兼ねてやろうと思います。# エディタが開く $ crontab -e # * * * * * 左から「分」「時」「日」「月」「曜日」 # 分 0-59 # 時 0-23 # 日 1-31 # 月 1-12 # 曜日 0-7 (0または7は日曜日) # * * * * * で毎分 # 下記の行を開いたエディタに追加 * * * * * cd [プロジェクトのパス] && php artisan schedule:run >> /dev/null 2>&1スケジュールへの登録
/app/Console/Kernel.php/** * Define the application's command schedule. * * @param \Illuminate\Console\Scheduling\Schedule $schedule * @return void */ protected function schedule(Schedule $schedule) { // 5分ごとに実行 $schedule->command('instagram:refresh') ->everyFiveMinutes(); }mysql> select * from instagram_tokens; +----+--------------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+---------------------+---------------------+ | id | access_token | token_type | expires_in | created_at | updated_at | +----+--------------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+---------------------+---------------------+ | 8 |トークン | bearer | 5156672 | 2020-09-22 03:35:01 | 2020-09-22 03:35:01 | | 9 |トークン | bearer | 5156371 | 2020-09-22 03:40:01 | 2020-09-22 03:40:01 | +----+--------------------------------------------------------------------------------------------------------------------------------------------------+------------+------------+---------------------+---------------------+ちゃんと設定通りに定期実行されていますね
簡単な表示画面を作成します
/app/Http/Controllers/InstagramController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class InstagramController extends Controller { public function index () { return view('instagram'); } }/resources/views/instagram.blade.php<html> <head> <title>HelloWorld</title> </head> <body> <h1>HelloWorld!</h1> </body> </html>サーバー起動
$ php artisan serve
http://127.0.0.1:8000/instagram
アクセスできればOK投稿した画像を取得
/app/Http/Controllers/InstagramController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\InstagramToken; class InstagramController extends Controller { public function index () { $baseUrl = "https://graph.instagram.com/me/media?"; // アクセストークン取得 $instagramToken = InstagramToken::select('access_token')->latest()->first(); $accessToken = env('INSTAGRAM_TOKEN'); if ($instagramToken->access_token) { $accessToken = $instagramToken->access_token; } // パラメーター設定 $params = array( 'fields' => implode(',', array('id','caption','permalink','media_url','thumbnail_url')), 'access_token' => $accessToken ); //curlセッション初期化 $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $baseUrl . http_build_query($params)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $responseText = curl_exec($ch); $result = json_decode($responseText, true); //セッション終了 curl_close($ch); return view('instagram', [ 'mediaData' => $result['data'], 'paging' => $result['paging'] ]); } }投稿した画像を表示
/resources/views/instagram.blade.php<html> <head> <title>HelloWorld</title> </head> <body> @foreach ($mediaData as $media) <a href="{{$media['permalink']}}" target="_brank" rel="noopener"> <img src="{{$media['media_url']}}" width="100px" alt="{{$media['caption']}}"> </a> @endforeach </body> </html>結果
最後に
実装方法について
Laravelでcommandを作成し、定期実行すると言うのは初めてだったので結構楽しかったです。アクセストークンは定期実行、投稿の取得は毎回APIを実行という方法を今回取っていたのですが、
APIリクエストの節約の為に1日1回夜中に投稿を取得するようにし,その結果をjsonファイルとして出力,またはDBに保存するなどすればリクエスト数を節約出来ると思いました。
もっとこう言う良い方法ある等あれば教えてもらえると嬉しいです。Instagram Basic Display APIについて
自分のブログなどにインスタで投稿したものを表示させたいなら、Instagram Basic Display API
で十分そうですね。今回は「InstagramのAPI使いたい!」と思ってやったのですが,よくよく考えたら僕自身が映える写真を投稿しているアカウントを持っていなかったので,今回のAPIだといい感じの写真が表示されませんでした。。。
- 投稿日:2020-09-21T02:00:00+09:00
Laravel CRUD処理を使った投稿アプリを作成する その9 バリデーションをRequestに記載する
目的
- アプリを作成する上で基本となるCRUD処理を有したLaravelアプリをチュートリアル的に作成する方法をまとめる
実施環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.5) ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) プロセッサ 2 GHz クアッドコアIntel Core i5 メモリ 32 GB 3733 MHz LPDDR4 グラフィックス Intel Iris Plus Graphics 1536 MB
- ソフトウェア環境
項目 情報 備考 PHP バージョン 7.4.3 Homwbrewを用いて導入 Laravel バージョン 7.0.8 commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする 前提条件
- 実施環境に近い環境が構築されていること。
- 筆者は下記の方法で環境構築を行った。
前提情報
- ソースコードはこちら→https://github.com/miriwo0104/laravel_crud/tree/master
- DockerやAWSなどは使用せずにMacのローカルに実施環境と同じLaravel開発環境を構築して実施する。
- チュートリアルで実際に筆者が作成したソースコードをGitHubにて公開予定である。
- CRUD処理の作成完了を最短目標にしてバリデーションなどは後々設定することとする。
- 実施環境と同じ環境がDockerやAWSで用意できるなら都度読み替えていただければ実施が可能だと思う。
- 公式ドキュメントと一冊の技術書を元に本記事を記載する。
- Laravel 7.x
- PHPフレームワーク Laravel Webアプリケーション開発 バージョン5.5 LTS対応
- 本記事はシリーズとして内容を分割する予定である。記事のタグ「miriwo_laravelチュートリアル」を本シリーズの記事に付与するのでそのほかの記事がみたい方は活用していただきたい。
- DBへの意図しないデータの流入を防ぐためバリデーションを実装する。
- 問い合わせの内容は「入力がされていること」のバリデーションルールを、新規投稿と投稿編集は「入力されており、かつ140文字以内であること」定義してバリデートする。
- バリデーションで弾かれた時にエラーが出力される様にする。
- 下記に目を通しておくと理解が早いかもしれない。
- バリデーションルールは下記の公式ドキュメントに数多く記載されているので実装できたら遊んでみるのもいいかもしれない。
この記事の読後感
- ユーザが入力する部分にバリデーションを実装することができ、バリデーションルールをRequestファイルに記載する。
概要
- Requestファイルの作成と記載
- コントローラファイルの記載修正
- 確認
詳細
Requestファイルの作成と記載
laravel_crudディレクトリで下記コマンドを実行し専用のリクエストファイルを作成する。
$ php artisan make:request ContentRequestlaravel_crudディレクトリで下記コマンドを実行し先に作成したリクエストファイルを開く。
$ vi app/Http/Requests/ContentRequest.php先に開いたリクエストファイルを下記の様に修正する。
laravel_crud/app/Http/Requests/ContentRequest.php<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class ContentRequest extends FormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { // 下記を修正する return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ // 下記を追記する 'content' => ['required', 'max: 140'], ]; } }laravel_crudディレクトリで下記コマンドを実行し専用のリクエストファイルを作成する。
$ php artisan make:request InquiryRequestlaravel_crudディレクトリで下記コマンドを実行し先に作成したリクエストファイルを開く。
$ vi app/Http/Requests/InquiryRequest.php先に開いたリクエストファイルを下記の様に修正する。
laravel_crud/app/Http/Requests/InquiryRequest.php<?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class InquiryRequest extends FormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { // 下記を修正する return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ // 下記を追記する 'content' => ['required'], 'name' => ['required'], // 上記までを追記する ]; } }コントローラファイルの記載修正
laravel_crudディレクトリで下記コマンドを実行しコントローラファイルを開く。
$ vi app/Http/Controllers/ContentController.php先に開いたファイルを下記の様に修正する。
laravel_crud/app/Http/Controllers/ContentController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Content; // 下記を追記する use App\Http\Requests\ContentRequest; class ContentController extends Controller { public function input() { return view('contents.input'); } // 下記を修正する public function save(ContentRequest $contentRequest) { // バリデーションルールとバリデート命令を削除する $input_content = new Content(); // 下記を修正する $input_content->content = $contentRequest['content']; $input_content->save(); return redirect('/output'); } public function output() { $contents_get_query = Content::select('*'); $all_contents = $contents_get_query->get(); return view('contents.output', [ 'all_contents' => $all_contents, ]); } public function delete(Request $request) { $contents_delete_query = Content::select('*'); $contents_delete_query->where('id', $request['content_id']); $contents_delete_query->delete(); return redirect('/output'); } public function edit($content_id) { $contents_edit_query = Content::select('*'); $contents_edit_query->where('id', $content_id); $edit_contents = $contents_edit_query->get(); $edit_content = $edit_contents[0]; return view('contents.edit', [ 'edit_content' => $edit_content, ]); } // 下記を修正する public function update(ContentRequest $contentRequest) { // バリデーションルールとバリデート命令を削除する $contents_update_query = Content::select('*'); // 下記を修正する $contents_update_query->where('id', $contentRequest['content_id']); $update_contents = $contents_update_query->get(); $update_content = $update_contents[0]; // 下記を修正する $update_content->content = $contentRequest['content']; $update_content->save(); return redirect('/output'); } }laravel_crudディレクトリで下記コマンドを実行しコントローラファイルを開く。
$ vi app/Http/Controllers/InquiryController.php先に開いたファイルを下記の様に修正する。
laravel_crud/app/Http/Controllers/InquiryController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Auth; use App\Mail\SendMail; // 下記を追記する use App\Http\Requests\InquiryRequest; class InquiryController extends Controller { public function input() { $user_infos = Auth::user(); return view('inquiries.input', [ 'user_infos' => $user_infos, ]); } // 下記を修正する public function send(InquiryRequest $inquiryRequest) { // バリデーションルールとバリデート命令を削除する // 下記を修正する $inquiry_content = $inquiryRequest->all(); Mail::to('admin@example')->send(new SendMail($inquiry_content)); return redirect(route('home')); } }確認
laravel_crudディレクトリで下記コマンドを実行しローカルサーバを起動する。
$ php artisan serve下記にユーザ認証後、下記にアクセスする。
何も入力せず「送信」をクリックし下記のようにエラーが出ることを確認する。
下記にユーザ認証後、下記にアクセスする。(コンテンツのidは1以外でも構わない)
何も入力せず「送信」をクリックし下記のようにエラーが出ることを確認する。
下記にユーザ認証後、下記にアクセスする。(コンテンツのidは1以外でも構わない)
何も入力せず「送信」をクリックし下記のようにエラーが出ることを確認する。
参考文献
- 投稿日:2020-09-21T01:59:36+09:00
Laravel CRUD処理を使った投稿アプリを作成する その8 バリデーションを実装する
目的
- アプリを作成する上で基本となるCRUD処理を有したLaravelアプリをチュートリアル的に作成する方法をまとめる
実施環境
- ハードウェア環境
項目 情報 OS macOS Catalina(10.15.5) ハードウェア MacBook Pro (13-inch, 2020, Four Thunderbolt 3 ports) プロセッサ 2 GHz クアッドコアIntel Core i5 メモリ 32 GB 3733 MHz LPDDR4 グラフィックス Intel Iris Plus Graphics 1536 MB
- ソフトウェア環境
項目 情報 備考 PHP バージョン 7.4.3 Homwbrewを用いて導入 Laravel バージョン 7.0.8 commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする 前提条件
- 実施環境に近い環境が構築されていること。
- 筆者は下記の方法で環境構築を行った。
前提情報
- ソースコードはこちら→https://github.com/miriwo0104/laravel_crud/tree/master
- DockerやAWSなどは使用せずにMacのローカルに実施環境と同じLaravel開発環境を構築して実施する。
- チュートリアルで実際に筆者が作成したソースコードをGitHubにて公開予定である。
- CRUD処理の作成完了を最短目標にしてバリデーションなどは後々設定することとする。
- 実施環境と同じ環境がDockerやAWSで用意できるなら都度読み替えていただければ実施が可能だと思う。
- 公式ドキュメントと一冊の技術書を元に本記事を記載する。
- Laravel 7.x
- PHPフレームワーク Laravel Webアプリケーション開発 バージョン5.5 LTS対応
- 本記事はシリーズとして内容を分割する予定である。記事のタグ「miriwo_laravelチュートリアル」を本シリーズの記事に付与するのでそのほかの記事がみたい方は活用していただきたい。
- DBへの意図しないデータの流入を防ぐためバリデーションを実装する。
- 問い合わせの内容は「入力がされていること」のバリデーションルールを、新規投稿と投稿編集は「入力されており、かつ140文字以内であること」定義してバリデートする。
- バリデーションで弾かれた時にエラーが出力される様にする。
- 下記に目を通しておくと理解が早いかもしれない。
- バリデーションルールは下記の公式ドキュメントに数多く記載されているので実装できたら遊んでみるのもいいかもしれない。
この記事の読後感
- ユーザが入力する部分にバリデーションを実装することができる。
概要
- バリデーションの実装
- エラー出力部分とデフォルト値の設定
- 確認
詳細
バリデーションの実装
laravel_crudディレクトリで下記コマンドを実行してコントローラファイルを開く。
$ vi app/Http/Controllers/ContentController.php先に開いたコントローラファイルのsaveアクションを下記の様に修正する。
laravel_crud/app/Http/Controllers/ContentController.phppublic function save(Request $request) { // 下記を追記する $rules = [ 'content' => ['required', 'max: 140'], ]; $this->validate($request, $rules); // 上記までを追記する $input_content = new Content(); $input_content->content = $request['content']; $input_content->save(); return redirect('/output'); }先に開いたコントローラファイルのupdateアクションを下記の様に修正する。
laravel_crud/app/Http/Controllers/ContentController.phppublic function update(Request $request) { // 下記を追記する $rules = [ 'content' => ['required', 'max: 140'], ]; $this->validate($request, $rules); // 上記までを追記する $contents_update_query = Content::select('*'); $contents_update_query->where('id', $request['content_id']); $update_contents = $contents_update_query->get(); $update_content = $update_contents[0]; $update_content->content = $request['content']; $update_content->save(); return redirect('/output'); }ContentController.phpの全体像を下記に記載する。
laravel_crud/app/Http/Controllers/ContentController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Content; class ContentController extends Controller { public function input() { return view('contents.input'); } public function save(Request $request) { // 下記を追記する $rules = [ 'content' => ['required', 'max: 140'], ]; $this->validate($request, $rules); // 上記までを追記する $input_content = new Content(); $input_content->content = $request['content']; $input_content->save(); return redirect('/output'); } public function output() { $contents_get_query = Content::select('*'); $all_contents = $contents_get_query->get(); return view('contents.output', [ 'all_contents' => $all_contents, ]); } public function delete(Request $request) { $contents_delete_query = Content::select('*'); $contents_delete_query->where('id', $request['content_id']); $contents_delete_query->delete(); return redirect('/output'); } public function edit($content_id) { $contents_edit_query = Content::select('*'); $contents_edit_query->where('id', $content_id); $edit_contents = $contents_edit_query->get(); $edit_content = $edit_contents[0]; return view('contents.edit', [ 'edit_content' => $edit_content, ]); } public function update(Request $request) { // 下記を追記する $rules = [ 'content' => ['required', 'max: 140'], ]; $this->validate($request, $rules); // 上記までを追記する $contents_update_query = Content::select('*'); $contents_update_query->where('id', $request['content_id']); $update_contents = $contents_update_query->get(); $update_content = $update_contents[0]; $update_content->content = $request['content']; $update_content->save(); return redirect('/output'); } }laravel_crudディレクトリで下記コマンドを実行してコントローラファイルを開く。
$ vi app/Http/Controllers/InquiryController.php先に開いたコントローラファイルのsendアクションを下記の様に修正する。
laravel_crud/app/Http/Controllers/InquiryController.phppublic function send(Request $request) { // 下記を追記する $rules = [ 'content' => ['required'], 'name' => ['required'], ]; $this->validate($request, $rules); // 上記までを追記する $inquiry_content = $request->all(); Mail::to('admin@example')->send(new SendMail($inquiry_content)); return redirect(route('home')); }InquiryController.phpの全体像を下記に記載する。
laravel_crud/app/Http/Controllers/InquiryController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Auth; use App\Mail\SendMail; class InquiryController extends Controller { public function input() { $user_infos = Auth::user(); return view('inquiries.input', [ 'user_infos' => $user_infos, ]); } public function send(Request $request) { // 下記を追記する $rules = [ 'content' => ['required'], 'name' => ['required'], ]; $this->validate($request, $rules); // 上記までを追記する $inquiry_content = $request->all(); Mail::to('admin@example')->send(new SendMail($inquiry_content)); return redirect(route('home')); } }laravel_crudディレクトリで下記コマンドを実行しローカルサーバを起動する。
$ php artisan serve下記にユーザ認証後、下記にそれぞれアクセスし内容を入力せずに送信ボタンをクリックし、ページ遷移せず同じページが再度読み込まれることを確認する。編集画面での確認はidが1以外のものでも良い。
エラー出力部分とデフォルト値の設定
laravel_crudディレクトリで下記コマンドを実行して新規投稿画面のビューファイルを開く。
$ vi resources/views/contents/input.blade.php開いたファイルを下記の様に修正する。
laravel_crud/resources/views/contents/input.blade.php<h1>input</h1> {{-- 下記を追記する --}} @error('content') {{ $message }} @enderror {{-- 上記までを追記する --}} <form action="{{route('save')}}" method="post"> @csrf {{-- 下記を修正する --}} <textarea name="content" cols="30" rows="10">{{ old('content') }}</textarea> <input type="submit" value="送信"> </form>laravel_crudディレクトリで下記コマンドを実行して投稿編集画面のビューファイルを開く。
$ vi resources/views/contents/edit.blade.php開いたファイルを下記の様に修正する。
laravel_crud/resources/views/contents/edit.blade.php<h1>edit</h1> {{-- 下記を追記する --}} @error('content') {{ $message }} @enderror {{-- 上記までを追記する --}} <form action="{{route('update')}}" method="post"> @csrf <textarea name="content" cols="30" rows="10">{{$edit_content['content']}}</textarea> <input type="hidden" name="content_id" value="{{$edit_content['id']}}"> <input type="submit" value="送信"> </form>laravel_crudディレクトリで下記コマンドを実行して投稿編集画面のビューファイルを開く。
$ vi resources/views/contents/edit.blade.php開いたファイルを下記の様に修正する。
laravel_crud/resources/views/contents/edit.blade.php<h1>edit</h1> {{-- 下記を追記する --}} @error('content') {{ $message }} @enderror {{-- 上記までを追記する --}} <form action="{{route('update')}}" method="post"> @csrf <textarea name="content" cols="30" rows="10">{{$edit_content['content']}}</textarea> <input type="hidden" name="content_id" value="{{$edit_content['id']}}"> <input type="submit" value="送信"> </form>laravel_crudディレクトリで下記コマンドを実行して問い合わせ送信画面のビューファイルを開く。
$ vi resources/views/inquiries/input.blade.php開いたファイルを下記の様に修正する。
laravel_crud/resources/views/inquiries/input.blade.php<form action="{{ route('inquiry.send') }}" method="POST"> @csrf <p>お問い合わせ内容</p> <textarea name="content" cols="30" rows="10"></textarea> {{-- 下記を追記する --}} @error('content') {{ $message }} @enderror {{-- 上記までを追記する --}} <p>お客様のお名前</p> <input type="text" name="name" value="{{ $user_infos['name'] }}"> {{-- 下記を追記する --}} @error('name') {{ $message }} @enderror {{-- 上記までを追記する --}} <p>お客様のメールアドレス</p> <p>{{ $user_infos['email'] }}</p> <input type="hidden" name="email" value="{{ $user_infos['email'] }}"> <br> <input type="submit" value="送信"> </form>確認
laravel_crudディレクトリで下記コマンドを実行しローカルサーバを起動する。
$ php artisan serve下記にユーザ認証後、下記にアクセスする。
何も入力せず「送信」をクリックし下記のようにエラーが出ることを確認する。
下記にユーザ認証後、下記にアクセスする。(コンテンツのidは1以外でも構わない)
何も入力せず「送信」をクリックし下記のようにエラーが出ることを確認する。
下記にユーザ認証後、下記にアクセスする。(コンテンツのidは1以外でも構わない)
何も入力せず「送信」をクリックし下記のようにエラーが出ることを確認する。
参考文献