- 投稿日:2020-03-19T23:28:27+09:00
Laravel pluckメソッドとか便利メソッド
- 投稿日:2020-03-19T23:28:27+09:00
Laravel plackメソッドとか便利メソッド
- 投稿日:2020-03-19T18:35:06+09:00
Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part9 ~最終回~
前回のパート
前回はtodo削除機能の実装を行いました
今回は残す最後の機能として、todoの更新機能の実装をやっていきます
今回が最後のパートになります
前回のパートはこちら→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part8Laravel側の実装
todoの更新に使うのは
TodoController.php
のupdate()
アクションになります
update()
アクションは/todo{id}
に対してPUTリクエストで呼び出されますそれでは
TodoController.php
を開きupdate()
アクションに下記を追加してくださいTodoController.phppublic function update(Request $request, $id) { $todo = Todo::find($id); $todo->text = $request->text; $todo->save(); return response('', 200); }引数の$idを受け取ってtodosテーブルからそのidに該当するレコードを所得して
$request->text
で送られてきたデーターに更新しています
Laravel側の実装はこれで終了ですVue側の実装
Todo.vue
を開き下記のように変更と追加をしてくださいTodo.vue<template> <div> <Header /> <div class="main-container"> {{ user.name }}のTodoリスト <v-text-field v-model="text" label="todo" required></v-text-field> <v-btn class="btn" @click="create">登録</v-btn> <template v-for="item in items"> <v-card max-width="450" class="mx-auto" style="marign-top: 10px" :key="item.id"> <v-list three-line> <v-list-item :key="item.id"> <v-list-item-content> <input type="text" v-model="item.text" @keydown.enter="update(item.id, item.text)"> //追加 <v-btn small @click="del(item.id)">完了</v-btn> </v-list-item-content> </v-list-item> </v-list> </v-card> </template> </div> </div> </template> <script> import Header from './Header'; import axios from 'axios'; export default { components: { Header }, metaInfo: { title: 'Todo', htmlAttrs: { lang: 'ja' } }, created () { const user = this.$store.getters['auth/user']; if (user === null) { this.$router.push('/login'); } axios.get('/api/todo/' + this.user.id) .then((res) => { this.items = res.data; }); }, computed: { user() { return this.$store.getters['auth/user']; } }, data () { return { items: null, text: '' } }, methods: { async create() { await axios.post('/api/todo', { user_id: this.user.id, text: this.text }); this.$router.go({ path: this.$router.currentRoute.path, force: true }); }, async del(id) { await axios.delete('/api/todo/' + id); this.$router.go({ path: this.$router.currentRoute.path, force: true }); }, async update(id, text) { //追加 if (event.keyCode !== 13) { return } await axios.put('/api/todo/' + id, { text: text }); this.flg = false; this.$router.go({ path: this.$router.currentRoute.path, force: true }); } } } </script> <style> .main-container { width: 500px; margin: auto; } .btn { margin-bottom: 20px; } </style>2箇所の追加を行いました
まずこの部分ですが
<input type="text" v-model="item.text" @keydown.enter="update(item.id, item.text)">
input要素に内容が書き込まれEnterキーを押すことでupdate()
メソッドが発火するようにしました
次にこの部分ですがTodo.vueasync update(id, text) { if (event.keyCode !== 13) { return } await axios.put('/api/todo/' + id, { text: text }); this.$router.go({ path: this.$router.currentRoute.path, force: true }); }if文の箇所ですが、この部分がなければtodoの変更でinputに日本語の入力をした際に
変換などでEnterキーを押すとそれで発火してしまいます
そのためif文での処理を追加しています
日本語入力の際の変換でのEnterをKeyCodewを299を返します
日本語入力の変換でのEnterではない(今回の場合はtodoの変更のEnter)の場合はKeyCodeを13を返します
本来発火させたいのは、後者のKeyCode13の場合です
なのでupdate()
メソッドの最初でこのEnterキーは13なのかどうかをチェックしています
この処理がなければ、Enterを押すたびに処理が走ってしまうため入力途中のものなどが登録されることになりますので注意してください次にLaravel側の
/todo
に対してtodoのidと変更内容をPUTでリクエストしています
これで、先ほど実装したLaravel側でのTodoController.php
のupdate()
アクションを呼び出すことができますここまでの実装で、todoの更新ができるようになっています
表示されているtodoをクリックし、違うものに書き換えてEnterキーを入力してみてください
正常に実装できていれば、todoが編集され画面に出力されているかと思います以上で本記事での全ての機能の実装が終わりました
会員登録、ログイン、ログアウト、todoの一覧表示、todoの新規作成、todoの削除、todoの更新
この機能を組み合わせればTodoリスト意外の開発でも同じ要領で色々な物が作れるかと思います最後に
今回は最後のパートとしてtodoの更新機能の実装を行いました
ここまでの9パート最後まで読んでいただきありがとうございました
少しでも、学習者の役に立てればと思いこの記事を作成しました
また、本記事では未熟である私自身が書いた記事のため
まだまだ、改善点やリファクタリング等もできるかと思いますので
このチュートリアルを進めて頂いた方々個人で取り組んで頂ければと思います。
また、間違った点や気になった点アドバイスなど御座いましたら
是非コメント頂ければと思っておりま
ありがとうございました。
- 投稿日:2020-03-19T17:53:29+09:00
Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part8
前回のパート
前回はtodoの一覧表示機能を作成しました
今回はtodoの完了時に押す削除機能を実装していきます
前回のパートはこちらVue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part7Laravel側の実装
todoの削除を行うのは
TodoController.php
のdestroy()
アクションを利用します
destroy()
アクションの中身の実装をやっていきます
TodoController.php
を開きdestroy()
アクションに下記を追加してくださいTodoController.phppublic function destroy($id) { Todo::find($id)->delete(); return response('', 200); }これで
destroy()
アクションが呼び出されたら、引数で受け取った該当するtodoの削除を行なえるようになりました
destroy()
アクションは/todo/{id}
の形でDELETEリクエストをすることで呼び出すことができるので
Vue側でそのtodoのidを付与しリクエストするよに実装しますVue側の実装
Todo.vue
を開き下記を追加してくださいTodo.vue<template> <div> <Header /> <div class="main-container"> {{ user.name }}のTodoリスト <v-text-field v-model="text" label="todo" required></v-text-field> <v-btn class="btn" @click="create">登録</v-btn> <template v-for="item in items"> <v-card max-width="450" class="mx-auto" style="marign-top: 10px" :key="item.id"> <v-list three-line> <v-list-item :key="item.id"> <v-list-item-content> <input type="text" v-model="item.text"> <v-btn small @click="del(item.id)">完了</v-btn> //追加 </v-list-item-content> </v-list-item> </v-list> </v-card> </template> </div> </div> </template> <script> import Header from './Header'; import axios from 'axios'; export default { components: { Header }, metaInfo: { title: 'Todo', htmlAttrs: { lang: 'ja' } }, created () { const user = this.$store.getters['auth/user']; if (user === null) { this.$router.push('/login'); } axios.get('/api/todo/' + this.user.id) .then((res) => { this.items = res.data; }); }, computed: { user() { return this.$store.getters['auth/user']; } }, data () { return { items: null, text: '' } }, methods: { async create() { await axios.post('/api/todo', { user_id: this.user.id, text: this.text }); this.$router.go({ path: this.$router.currentRoute.path, force: true }); }, async del(id) { //追加 await axios.delete('/api/todo/' + id); this.$router.go({ path: this.$router.currentRoute.path, force: true }); } } } </script> <style> .main-container { width: 500px; margin: auto; } .btn { margin-bottom: 20px; } </style>完了ボタンにクリックイベントを配置しました
イベントで呼び出されるメソッドの引数にitem.id
として、そのtodoのidを渡しています
後はメソッド側でLaravel側の/todo/{id}
としてDELETEリクエストを送信して、store()
アクションを呼び出し
削除処理を実装していますここまでの実装で実際にtodoの削除ができるようになっています
登録したタスクの完了ボタンをクリックし、そのtodoが消えればOKです
確認してみましょうこれで削除機能の実装は終わりです
終わりに
今回はtodoの削除機能の実装を行いました
次回はtodoの更新機能の実装を行います
次回が最後のパートになります次回のパート→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part9 ~最終回~
- 投稿日:2020-03-19T17:22:10+09:00
Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part7
前回のパート
前回は、todoの新規登録機能を実装しました
今回は前回の登録した内容を表示する機能の実装を行っていきます
前回のパートはこちら→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part6Laravel側の実装
TodoController.php
のshow()
アクションに機能を追加していきます
show()
は/todo/{id}
の形でGETリクエストを送ることで呼び出されます
show()
に下記を追加してくださいTodoController.phppublic function show($id) { $data = Todo::where('user_id', $id)->get(); return $data; }引数で受け取った
user_id
と一致するレコードを所得しているだけの処理になります
Laravel側の処理は以上です次にVue側でそれを所得し表示させます
Vue側の実装
Todo.vue
を開き下記を追加してくださいTodo.vue<template> <div> <Header /> <div class="main-container"> {{ user.name }}のTodoリスト <v-text-field v-model="text" label="todo" required></v-text-field> <v-btn class="btn" @click="create">登録</v-btn> <template v-for="item in items"> <v-card max-width="450" class="mx-auto" style="marign-top: 10px" :key="item.id"> <v-list three-line> <v-list-item :key="item.id"> <v-list-item-content> <input type="text" v-model="item.text"> <v-btn small>完了</v-btn> </v-list-item-content> </v-list-item> </v-list> </v-card> </template> </div> </div> </template> <script> import Header from './Header'; import axios from 'axios'; export default { components: { Header }, metaInfo: { title: 'Todo', htmlAttrs: { lang: 'ja' } }, created () { const user = this.$store.getters['auth/user']; if (user === null) { this.$router.push('/login'); } axios.get('/api/todo/' + this.user.id) //追加 .then((res) => { this.items = res.data; }); }, computed: { user() { return this.$store.getters['auth/user']; } }, data () { return { items: null, text: '' } }, methods: { async create() { await axios.post('/api/todo', { user_id: this.user.id, text: this.text }); this.$router.go({ path: this.$router.currentRoute.path, force: true }); } } } </script> <style> .main-container { width: 500px; margin: auto; } .btn { margin-bottom: 20px; } </style>画面がレンダリングされる際に、created()を使い
/api/todo/
にgetリクエストを行い
Laravel側のルートで定義された/todo
のstore()
アクションを呼び出すようにしています
store()
では、その指定されたユーザーのIDから該当するデーターを所得してreturnするように実装したので
Vue側ではそれを受け取り、dataのitemsに格納しています
後は、そのitemsの中身をv-forでループさせて表示させていますここまでの実装で、前回登録した内容のデーターが表示されていれば
正常にできていることになりますまた、一度todoの登録を行い新規で登録したものが追加されて表示されているか
確認してみてください終わりに
今回はtodoの一覧表示機能を実装しました
残る機能は、todoの削除とtodoの更新になります
次回はtodoの削除(完了)を実装していこうと思います次回のパートはこちら→Vue CLI × Laravel × VuetifyでCSSいらずの爆速開発でTodoリストを作る part8
- 投稿日:2020-03-19T12:39:58+09:00
【Laravel】php artisan migrateでハマったので、XAMPP環境でPostgreSQLを使ってみた。
migrateでエラーが出まくった。。。
いつもお世話になっているTechpitの教材で学習していた際に、migrateで思いっきりハマり、解決できなかったのでXAMPPでPostgreSQLを使えるようにしてみました。その際のメモです。
学習に使用している教材のリンク:
https://www.techpit.jp/p/laravel-vue-snsこちら作りながら学べる学習教材で楽しみながらミドルウェア、認可、フロントエンドとの連携などかなり深いところまで学べるのでめちゃくちゃおススメです!!
自身の学習環境に関して
教材ではMac、Docker、PostgreSQLを用いて学習します。僕の場合はWindowsユーザーでDocker(Docker for Windows)の環境構築を以前挫折した経緯があったので、Windows、XAMPP、MariaDB(MySQL)で学習していました。
つまり、教材をじぶんの環境に合わせて読み替える必要がありました。
(僕にこれができるスキルはまだなかったってことです。。。泣)
データベースの構成
この教材のデータベースの構成は以下になります。(無料で見れる範囲の内容ですので引用させていただいております。)
順番としては、articlesテーブルを作った後に、likesテーブルを作るのですが、likesテーブルを作ろうとしたところエラーが出るようになってしまいました。(超絶序盤。)
どうハマったのか
※これに関しては解決できなかったので、原因分かり次第追記します。※どうやら外部キー制約関連で違いがある(負の値の無い数値型にするのがポイント)とのことです。
嘆いていたところやんばるさん(著者)からご教授いただきました。ありがとうございます。泣
参考(教えていただきました。):
https://qiita.com/0w0/items/4a9cb7d27794bfb93d46#%E5%8E%9F%E5%9B%A0さっそくご教示いただいた通り、unsigned()を付けて、php artisan migrateを実行!!
ところが。。。
SQLSTATE[HY000]: General error: 1005 Can't create table laravel_vue_sns.articles (errno: 150 "Foreign key constraint is key (user_id) references users (id))
⇒laravel_vue_sns
.articles
を作成できません(errno:150"外部キー制約はキー(user_id
)はusers
(id
)を参照します)
SQLSTATE[HY000]: General error: 1005 Can't create table laravel_vue_sns.articles (errno: 150 "Foreign key constraint is incorrectly formed") (SQL: alter tarticles(errno: 150 "Foreign key constraint is incorrectly formed") (SQL: alter tablearticlesadd constraintarticles_user_id_foreignforeign key (user_id) referencesusers(id`))⇒
laravel_vue_sns
.articles
を作成できません(errno:150"外部キー制約の形式が正しくありません ")(SQL:alter tarticles(errno:150"外部キー制約が正しくありません (SQL:変更テーブル
articles制約の追加
articles_user_id_foreign外部キー(
user_id)参照
users(
id`))こうなる。
続いて教えていただいたQiitaの記事を参考に自分のスクリプト見ながら睨めっこ。
increments()
で作ったカラムには、実は裏でunsined(符号無し)属性
が付与される。要は採番項目なので正の値しか登録できないわけだが、役割テーブル側のuser_id
とauthority_id
には同様の制約を付けていない。https://qiita.com/0w0/items/4a9cb7d27794bfb93d46#%E5%8E%9F%E5%9B%A0
自分のマイグレーションファイルでは、bigIncrementsで記載していることに気付く。違いを調べてみました。
参考:
https://qiita.com/fuubit/items/17f3eb306c64ede163d2
どうやらbigIncrements()は負の値も登録できてしまうっぽい。ってことで、全てincrements()に変えてみました。
が、先ほどと同様にエラーが出てしまいました。。。
解決できず。。。泣
環境の違いだけでここまで躓くものかと痛感。。。
(何回目だ。。。)
XAMPPでPostgreSQLを使ってみた。
ってことで、キッパリ諦めてXAMPPでPostgreSQLを使う形に挑戦してみました。(Dockerにも再挑戦しましたがcompose upができず再挫折。。。)参考:
https://tasulife-23.com/xampp-postgresql/この記事では、PHPファイルからPostgreSQLまでのつなぎ方が記載されています。
ざっくりこんな内容です。
その後、Laravelに紐づけるためには.envファイルを編集する必要があります。
DB_CONNECTION=pgsql DB_HOST=localhost DB_PORT=5432 DB_DATABASE=test DB_USERNAME=postgres DB_PASSWORD=secret(ここはご自身で設定したパスワードを記載してください。)
僕の場合はこんな感じです。別途、データベースを用意する必要があるのでデータベースを作成。
psql -U postgres -c "create database test;
その後、マイグレーション。無事、マイグレーションすることができました。
- 投稿日:2020-03-19T10:33:37+09:00
備忘録集[Vue.js+Laravel+docker]
一つの記事に書く程ではないけれども、
ハマった所を今後同じ所でハマった同志のため、
また物忘れが最近酷いので再度自分がハマらないため
自分が躓いた所を備忘録集として残します。
基本的だけれども見落としやすい所が中心です。備忘録なので書きなぐりの文章が多いです。
また間違い等があるかもしれないので、
都度修正していきます。Javascript関連:VueJS,typescript,axios等
1.axiosのdeleteの方法
postとは異なる方法で設定する必要がある。
axios.delete('url', params: { foo: 'bar' } ).then( //以下省略 );2.[Vue.js]async,awaitでreturnの結果としてaxiosでgetしたデータを取得する。
下の例はupdateDate関数でaxiosを使っている。
このupdateDate関数は外部から呼び出され、this.Dataの値を更新している。
しかしthisを使用しているので、thisに依存している。
依存を解消するなら、axiosの結果をupdateDataの外で受け取るべき。
しかしaxiosはPromise型なので、thenの内部でreturnを書いても値を返さない。改善前methods:{ updateData(url) { //データ取得 axios .get( url ) .then(response => { this.Data=response; //下のように書いてもresponseを返さない //return respose; }) .catch(error => { console.log(error); }) }, }そこでasync,awaitを利用し以下のように書き直す。
then以降まで書かないでもaxios.get(url)までで,
結果を返してくれる。参考:https://github.com/axios/axios
例1.thisをupdateDataの外部に出すことができた.mounted: async function() { let url = "どこかのurl"; try { this.Data = await this.updateTable(url); } catch (err) { console.log(err); } }, methods: { async updateData(url) { //axiosでデータ取得.get以降にthenを書かない。 return axios.get(url); }例2async function updateData2(url) { try { const response = await axios.get(url); return response; } catch (error) { console.error(error); return error; } }注意:axiosをVue.jsのmounted内部で使っている。
Axiosは例外処理も含めて多用する可能性が高いので、
慣れてきたらaxios等の非同期処理を担うクラスを作成したほうがコードが散乱しないので良い。3.tr等に普通にtransition-groupしてもアニメーションはつかない
htmlの仕様によりliやtr等のタグはtableタグ直下等の特殊な条件でしか処理されない。
なので、tableとtrの間に普通にtransition-groupしてもtr以下が表示されなくなる。失敗例<tbody name="table-row"> <transition-group> <tr v-for="data in showData" class="table-row-item" :key="data.id"> <!--ここは表示されない.transition-groupをdiv等にしても同じ挙動になる.--> </tr> </transition-group> </tbody>対策の一例は、tbodyにis="transition-group"をつけること。
tbodyにisをつける回避策<tbody name="table-row" is="transition-group"> <tr v-for="data in showData.data.data" class="table-row-item" :key="data.title">他の対策も複数あるので、必要な時は参考urlを参照。
4.アップロードされた画像ファイルのプレビュー表示方法 + URL.createObjectURLの仕様
画像の出力<div class="col-sm-1"> <img class="icon-image border border-dark" :src="iconimg" /> </div>ファイルのアップロードを入力するhtmlタグは省略。
ファイルが入力された後、下のselectedFile関数を通して画像を格納する。selectedFile(event) { //必要に応じてkeyは変更 this.iconfile = event.target.files[0]; //プレビュー用のイメージ格納 if (this.iconfile.type.startsWith("image/")) { //ObjectURLを生成 this.iconimg = window.URL.createObjectURL(this.iconfile); } },以下はjavascriptのcreateObjectURLの仕様の話。
createObjectURL(object)
は、
与えられたobjectに対してアクセス可能となるURLを生成している。
このURLはクライアントのブラウザのメモリ上に保存されているblob(いわゆる生のデータ)を参照する。
アップロードされたファイルはクライアント上ではFileオブジェクトで保存されているが、
File自体がblobを継承しているため、createObjectURLでのURL生成が可能となる。
なので、createObjectURL関数の引数となるobjectはfile,blob,MediaSourceのどれかでなくてはならない。
生成されたブラウザを閉じるまでURLは有効。
ただ一度ブラウザに読み込まれればURLは必要ないので、可能ならば削除したほうが良い。
window.URL.revokeObjectURL(file);
でURLの削除が可能。参考:
https://developer.mozilla.org/ja/docs/Web/API/File
https://qiita.com/azu369yu/items/8998e1e1536a5acfb7b3
https://qiita.com/iLLviA/items/c24f385ca3334c05a6825.[typescript+Vue.js]子コンポーネントにて、propsを定義する際にはundefinedに注意
参考:https://qiita.com/kyokoshimizu/items/ee6c6e6b905b8aa101fa
参考https://tech-up.hatenablog.com/entry/2019/03/15/152258前提:vue-property-decoratorをimportしている。
@Prop() public name:string;のようにVue.jsのpropsをtypescriptで書くと
Property '----' has no initializer and is not definitely assigned in the constructor.というエラーが出て怒られ、コンパイルができないケースがある。
しかし@Prop() public name:string = "";と初期化したらしたで、コンパイルも稼働はするが、コンソールには
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "propsValue"とエラーが出てしまう。
この場合、前者はtypescriptのエラーで後者がVue.jsのエラーになる。原因
typescriptの設定でstrictPropertyInitializationという設定がオンになっているためである。
strictPropertyInitializationは、「undefinedの許容されてない型を初期化させる」という設定になる。
要するに変数に初期値設定しろって設定。
最初に定義したPropsはstring型であるが、何も定義されていないのでundefinedが代入される。
string型にはundefinedが許容されていないため、strictPropertyInitializationによりエラーが発生した。
2回目のPropsのように初期化すればstrictPropertyInitializationによるエラーは解決しコンパイルは可能になるが、
これは子コンポーネントでpropsを書き換えているので、今後はVue.jsがエラーを発生させた。対策
四苦八苦した過程が残るけど自分のお勧めは4番1.tsconfig.jsonに以下を記述しstrictPropertyInitializationの設定をオフにする
strictPropertyInitialization:false但し全体に影響する。
2.any型やstringならばUnion型に変更しundefinedで対応できるようにする。
@Prop() public name:string|undefined;ただし、number型の場合はundefinedまたはnullとunion型にできないので、
この解決はできない。@Prop() public name:any;anyはどの型でも機能する。但しanyになるので型の意味があまりなくなる。
stringやnumberのような複雑じゃない型の時までanyにするのは悲しい。3.そもそも@component以下に書く
@Component( { props:{ placeholder:String, } } )但しexport以下で呼び出せなくなる。
4.型宣言の際に!をつける、または?をつける
参考:https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-7.html#strict-class-initialization
参考:https://dev.classmethod.jp/server-side/typescript-assertions/@Prop() public name!:any;!はコンパイラにこの型はnon-nullですよと伝える意味がある。
初期化されてないが実際には外部で変数が代入されている(丁度今回みたいな)場合に使える。
ちなみに@Prop()
の中身にはoptionが設定できる。ソースよりexport interface PropOptions<T=any> { type?: PropType<T>; required?: boolean; default?: T | null | undefined | (() => T | null | undefined); validator?(value: T): boolean; }defaultとか設定したいときは次のような感じ
@Prop({default:"text"}) public type!:string;ちなみに上のソースコードでも出現しているが、!の代わりに?をつけても解決する。
?は代入されてなくても構わない、という意味になる。6.[Vue.js]vue-routerのto属性に対してparamを設定しpropを渡したい時、pathではなくnameでurlを呼び出さないといけない
<router-link :to="{name:'hoge',params:{huga: 'hage'}}" >でないといけない。router.jsの方でnameで設定しないとparamsが有効にならない。
pathを設定するとurlに直接paramsを組み込まなければならない。Laravel
1.モデルでSELECTする時にidを取得しないと、そのインスタンスにsaveもupdateもできない
大ハマり
参考:https://qiita.com/moimoinon/items/5adb4b179e3c25d189a2悪い例$data = Article::select('title','updated_at')->with('hashtags:name')->get();例のようにモデルのidを取得していないインスタンスにsaveメソッドを使用して更新しようとした場合、
saveの結果としてtrueが返されてもデータベース上では更新されない。
この後の例等、予期せぬ挙動を生むことが多いので、selectする時は基本的にidは取得したほうが良い。2.EagerLoadを使う場合、SELECTでidを取らないとwithで参照してくれない
参考:https://mseeeen.msen.jp/laravel-5-5-get-specified-column-with-with/
relationのwithも、idを軸にリレーション先のデータを取得している。
よって、もしSELECT元でidが選択されていない場合、withの参照先のデータも取得されない。良い例//もしidのカラムを取得していない場合はhashtagsが空になってしまう $data = Article::select('title','updated_at','id')->with('hashtags:name')->get();3.belongsToの場合のモデル名は単数。データ取得の際も関数でなくプロパティを通して取得。
HasManyと同じつもりで複数形にすると、参照先モデルの取得が正しくされない。
悪い例public function admins(){ return $this->belongsTo(Admin::class); }belongsToの参照先は1対多の1側なので、単数にしなければならない。
良い例public function admin(){ return $this->belongsTo(Admin::class); }リレーション先のデータを取得する際も単数形で指示する。
プロパティでアクセスできるのが大きな違い。例//adminに対して()をつけずにプロパティでアクセスできる。 public function scopeGetAdminName($query,$id){ return $query->find($id)->admin->name; } //EagerLoad,withのadminが単数形になるのがhasManyの時との違い public function scopeWithAdmin($query){ return $query->with('admin:id,name'); }その他
1,[docker] php:7.4.2-apacheのdockerイメージでドキュメントルートを変更する方法
/etc/apache2/sites-available/000-default.confのドキュメントルートを変更
000-default.conf<VirtualHost *:80> # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request's Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. #ServerName www.example.com ServerAdmin webmaster@localhost #ここを変更 DocumentRoot /var/www/html/