- 投稿日:2020-06-19T18:17:39+09:00
element-uiのvalidatorの使い方
概要
laravel+vueで作ったWebサイトでバリデーション処理を作ったのでメモ。
formのattributeを使ったバリデーション
el-formとel-form-itemの属性を使ってバリデーションを組む。
コード量が少ないがテーブルのように複数アイテムがある場合や、APIを叩いてチェックしたい場合など静的ルールに表現できない場合は使えない。<el-form ref="formData" :model="formData" label-position="top"> <el-form-item :rules="rules" :prop="propname"> ・・・ </el-form-item> </el-form> (略) // バリデーション実行 const fm: any = _this.$refs["formData"]; fm.validate((valid, fields) => { // バリデーションNGの場合は処理中断 if (valid === false) { // 処理完了通知 _this.$message({ message: "入力内容が正しくない項目があります、赤色のエラー部分をご確認ください。", type: "warning", duration: 0, showClose: true }); return; } //バリデーションOKの処理 ・・ }formのvalidateメソッドをコールするとコールバックで結果が返ってくる。
validがbooleanのバリデーションOK/NG、fieldsにNG時の詳細(フィールド名とルールで指定したエラーメッセージのセット)が入ってくる。propnameにチェック対象のデータ変数を指定する。
rulesがバリデーションルール。以下にいくつかの例。必須チェック
private rules: Object[] = []; let requiredRule = { required: true, message: "入力必須です。", trigger: "blur" }; this.rules.push(requiredRule);郵便番号
let zipRules = { pattern: /^[0-9]{3}-[0-9]{4}$/, message: "正しい形式で入力してください。 例)123-4567", trigger: "blur" }; this.rules.push(zipRules);電話番号・FAX番号
let telFaxRules = { pattern: /^[-0-9]*$/, message: "正しい形式で入力してください。 例)1234-56-7890", trigger: "blur" }; this.rules.push(telFaxRules);let emailRules = { type: "email", message: "メールアドレス形式で入力してください。", trigger: "blur" }; this.rules.push(emailRules);全角チェック
// 英字 if (_this.charPattern.indexOf(CharPatternEnum.Alphabet) >= 0) { charPatternNames.push("英字"); regExpPattern += "a-zA-Z"; } // 数字 if (_this.charPattern.indexOf(CharPatternEnum.Numeric) >= 0) { charPatternNames.push("数字"); regExpPattern += "0-9"; } // カタカナ if (_this.charPattern.indexOf(CharPatternEnum.Katakana) >= 0) { charPatternNames.push("カタカナ"); regExpPattern += "ァ-ヶー"; } // スペース if (_this.charPattern.indexOf(CharPatternEnum.Space) >= 0) { charPatternNames.push("スペース"); regExpPattern += " "; } // ハイフン if (_this.charPattern.indexOf(CharPatternEnum.Hyphen) >= 0) { charPatternNames.push("ハイフン( ‐ )"); regExpPattern += "‐"; } // 全角以外の定義が無い場合の処理 if (charPatternNames.length === 0) { regExpPattern = "^\x00-\xFFァ-ンヲー゚゙"; } // 正規表現パターン終端処理 regExpPattern = "^[" + regExpPattern + "]*$"; // メッセージ作成 if (charPatternNames.length >= 2) { charPatternMsg += "の"; } charPatternMsg += charPatternNames.join("・") + "で入力してください。"; // ルールに追加 let charPatternRules = { pattern: new RegExp(regExpPattern), message: charPatternMsg, trigger: "blur" }; this.rules.push(charPatternRules);半角チェック
// 半角の場合 charPatternMsg += "半角"; // 英字 if (_this.charPattern.indexOf(CharPatternEnum.Alphabet) >= 0) { charPatternNames.push("英字"); regExpPattern += "a-zA-Z"; } // 数字 if (_this.charPattern.indexOf(CharPatternEnum.Numeric) >= 0) { charPatternNames.push("数字"); regExpPattern += "0-9"; } // カタカナ if (_this.charPattern.indexOf(CharPatternEnum.Katakana) >= 0) { charPatternNames.push("カタカナ"); regExpPattern += "ァ-ンヲー゚゙"; } // 記号 if (_this.charPattern.indexOf(CharPatternEnum.Symbol) >= 0) { charPatternNames.push("記号"); // todo: とりあえず全ての記号を網羅したが、使わなそうな記号は省いた方が良いかも。。@2020/01/28 s.aono regExpPattern += "\x20-\x2F\x3A-\x40\x5B-\x60\x7B-\x7E"; } // スペース if (_this.charPattern.indexOf(CharPatternEnum.Space) >= 0) { charPatternNames.push("スペース"); regExpPattern += " "; } // ハイフン if (_this.charPattern.indexOf(CharPatternEnum.Hyphen) >= 0) { charPatternNames.push("ハイフン( - )"); regExpPattern += "\\-"; } // 半角以外の定義が無い場合の処理 if (charPatternNames.length === 0) { regExpPattern = "\x20-\x7E\uFF65-\uFF9F"; } // 正規表現パターン終端処理 regExpPattern = "^[" + regExpPattern + "]*$"; // メッセージ作成 if (charPatternNames.length >= 2) { charPatternMsg += "の"; } charPatternMsg += charPatternNames.join("・") + "で入力してください。"; // ルールに追加 let charPatternRules = { pattern: new RegExp(regExpPattern), message: charPatternMsg, trigger: "blur" }; this.rules.push(charPatternRules);async-validatorを使ったカスタムバリデーション
テーブルのように複数アイテムがある場合や、APIを叩いてチェックしたい場合など動的にチェックしたい場合に使う方法。
実はel-formもasync-validatorを使っている。this.validate(function(valid: boolean) { // バリデーションNGの場合は処理中断 if (!valid) { // 処理完了通知 _this.$message({ message: "入力内容が正しくない項目があります、赤色のエラー部分をご確認ください。", type: "warning", duration: 0, showClose: true }); return; } ここにバリデーションOK時の処理 } //バリデーション実体 validate(callback) { const _this = this; _this.serviceTypeMstData.forEach(row => { _this.checkInput(row, [ "service_type_code", "service_item_code", "service_type_display_name" ]); }); var ret = true; _this.serviceTypeMstData.forEach(row => { if (row.isValidateError) { ret = false; } }); callback(ret); } //必須項目の入力チェック checkInput(row: ServiceTypeMasterExData, targets: string[]) { const _this = this; var rules = {}; targets.forEach((value: any, index: any) => { rules = Object.assign(rules, this.getRule(value)); }); var validator = new schema(rules); validator.validate(this.getValidateObject(row), (errors, fields) => { if (errors && !row.isAddButton) { // バリデーションエラー時 errors.forEach((value: any, index: any) => { row.validate_error[value["field"]] = value["message"]; }); } else { targets.forEach((value: any, index: any) => { row.validate_error[value] = ""; }); } row.isValidateError = (function(row) { for (var key in row.validate_error) { if (row.validate_error[key] != "") { return true; } } return false; })(row); }); } //対象に絞ったバリデーションルール取得 getRule(name: string) { return { service_type_code: { service_type_code: [{ required: true, message: "入力必須です。" }] }, service_item_code: { service_item_code: [{ required: true, message: "入力必須です。" }] }, service_type_display_name: { service_type_display_name: [{ required: true, message: "入力必須です。" }] } }[name]; } //バリデーション対象オブジェクト作成 getValidateObject(row: ServiceTypeMasterExData): object { return { service_type_code: row.service_type_code, service_item_code: row.service_item_code, service_type_display_name: row.service_type_display_name }; }静的ルールならel-formの時に使ったルールで記述できる。
動的ルールならcheckInputで判定処理を入れて結果をerrorsにbooleanで返し、fieldsに詳細をフィールド名(キー名:field)とメッセージ(キー名:message)で返せばいい。
- 投稿日:2020-06-19T17:26:01+09:00
el-uploadを使ったファイル添付機能
概要
laravel+vueで作成したWebサイトにて添付ファイル機能を実装したのでメモ。
フロント側のUIはelement-uiのel-uploadで作った。コード
vue側
<el-row :gutter="24" class="attachment-row"> <el-col :span="24"> <span class="item-label"><i class="fas fa-paperclip icon"></i>添付ファイル</span> <el-upload action="#" list-type="text" class="attachments-upload" :before-remove="beforeAttachmentsRemove" :on-change="addAttachments" :file-list="attachmentsList" :auto-upload="true" :show-file-list="true" :multiple="false" :drag="true" :limit="attachments_limit" :http-request="AttachmentsHttpRequest" > <i class="el-icon-upload"></i> <div class="el-upload__text"> ここにドラッグするか <em>ここをクリックして</em>アップロードしてください。 </div> <div slot="file" slot-scope="{ file }"> <div class="contents" :class="{ delete: file.isDelete }"> <span v-if="file.isDelete" class="el-upload-list__item-deleted"> <span class="el-upload-list__item-label"> <span class="each-row">削除は更新実行後に反映されます。</span> </span> </span> <li> <div v-if="!file.isUploaded"> <i class="el-icon-document icon"></i> <span v-if="!file.isUploaded" class="el-upload-list__item-noactions"> <span class="el-upload-list__item-label"> <span class="each-row">アップロード</span> <span class="each-row">待ち</span> </span> </span> <span class="filename">{{ file.name }}</span> <i class="el-icon-close" :disabled="file.isDelete" @click="deleteAttachments(file)" ></i> </div> <div v-else class="available-download"> <i class="el-icon-document icon" @click="downloadAttachment(file)"></i> <span class="filename" @click="downloadAttachment(file)">{{ file.name }}</span> <i class="el-icon-close close-icon" :disabled="file.isDelete" @click="deleteAttachments(file)" ></i> </div> </li> </div> </div> </el-upload> </el-col> </el-row> (略) private attachments_limit: number = 10; private attachmentsList: AttachementData[] = []; private fileReader: FileReader = new FileReader(); //添付ファイル追加(AttachmentsHttpRequestより後で呼ばれる) addAttachments(file: any, fileList: any) { // File size limitation const isLt5M = file.size / 1024 / 1024 < 100; if (!isLt5M) { this.$message.error("アップロードできるファイルサイズは100Mまでです。"); this.deleteAttachments(file); return false; } // Exceed limit if (this.attachmentsList.length >= this.attachments_limit) { this.$message.error("アップロードできるファイルは" + this.attachments_limit + "つまでです。"); this.deleteAttachments(file); return false; } file.id = file.uid; file.isUploaded = false; file.isDelete = false; this.attachmentsList.push(file); } //添付ファイル削除 deleteAttachments(file: any) { if (file.isUploaded) { //アップロード済み //画面表示リストの削除フラグ立てる let t = this.attachmentsList.filter(function(e) { return e === file; }); t[0].isDelete = true; //サーバへ送るリストの削除フラグを立てる let t2 = this.minute.attachments_base64.filter(function(e) { return e.id == file.uid; }); t2[0].isDelete = true; } else { //未アップロード //画面表示リストから消す this.attachmentsList = this.attachmentsList.filter(function(e) { return e !== file; }); //サーバへ送るリストから消す this.minute.attachments_base64 = this.minute.attachments_base64.filter(function(e) { return e.id != file.uid; }); } } //添付ファイル追加時のアップロード AttachmentsHttpRequest(options: any) { let file = options.file; let filename = file.name; if (file) { this.fileReader.readAsDataURL(file); } this.fileReader.onload = () => { if (!this.minute.attachments_base64.length) { this.minute.attachments_base64 = []; } this.minute.attachments_base64.push({ id: file.uid, filetype: file.type, original_filename: filename, comment: "", //アップロード時は空 base64data: this.fileReader.result, isUploaded: false, isDelete: false }); }; } //画面初期表示時に既存添付ファイルを反映する defaultAttachmentsListLoad(data: Attachement[]) { this.attachmentsList = []; data.forEach((value, index) => { if (this.attachmentsList.length < this.attachments_limit) { this.attachmentsList.push({ id: value.id, name: value.original_filename, comment: value.comment, isUploaded: true, isDelete: false, uid: value.id, url: "" }); } }); } //添付ファイルの属性入力時にdeleteキーやBackSpaceキーでリスト削除が走らないようにするための処理 beforeAttachmentsRemove(file, fileList) { return false; } /** * 添付ファイルダウンロード */ downloadAttachment(file: any) { const _this = this; axios({ url: "/api/minute/download/attachment", params: { minute_id: this.minute.id, attachment_id: file.uid }, method: "GET", responseType: "blob" // これがないと文字化けする }) .then(res => { const blob = new Blob([res.data], { type: res.data.type }); //レスポンスヘッダからファイル名を取得します var fileName = res.headers["download_filename"]; fileName = decodeURI(fileName).replace(/\+/g, " "); //ダウンロードします saveAs(blob, fileName); }) .catch(error => { var errorMsg = "不明"; // 通知 _this.$message({ message: "実行に失敗しました。[" + errorMsg + "]", type: "error", duration: 0, showClose: true }); }); }バックエンド側
[画面表示時のメタデータ取得]//添付ファイル(メタ情報だけ返す) $attachments_base64 = []; if ($minute->attachments) { $attachment_paths = json_decode($minute->attachments); foreach ($attachment_paths as $file) { $attachments_base64[] = [ 'id' => $file->id, 'original_filename' => $file->original_filename, 'isUploaded' => true, 'isDelete' => false ]; } } $minute['attachments_base64'] = $attachments_base64;[保存時]//添付ファイルをファイルとして保存する $attachment_json = []; foreach ($request->attachments_base64 as $file) { $path = str_pad($minute->id, 10, '0', 0) . '_' . $file['id']; if ($file['isUploaded'] && !$file['isDelete']) { //アップロード済みで削除でない->何もしない $attachment_json[] = ['id' => $file['id'], 'path' => $path, 'original_filename' => $file['original_filename']]; } elseif ($file['isUploaded'] && $file['isDelete']) { //アップロード済みで削除する->実体ファイルを削除しJSONに書き込まない if (Storage::disk('local')->exists('/minute/' . $path)) { Storage::disk('local')->delete('/minute/' . $path); } } elseif (!$file['isUploaded']) { //アップロード済されていない->アップロードする $fileData = $file['base64data']; if (count(explode(';', $fileData)) > 1) { list(, $fileData) = explode(';', $fileData); } if (count(explode(',', $fileData)) > 1) { list(, $fileData) = explode(',', $fileData); } $fileData = base64_decode($fileData); Storage::disk('local')->put('/minute/' . $path, $fileData); $attachment_json[] = ['id' => $file['id'], 'path' => $path, 'original_filename' => $file['original_filename']]; } } $minute->attachments = json_encode($attachment_json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); $minute->save(); //DBに添付ファイルパスを更新[ダウンロード時]public function attachmentDownload(Request $request) { $minute = Minutes:: firstOrNew(['id' => $request->minute_id]); //添付ファイル if ($minute->attachments) { $attachment_paths = json_decode($minute->attachments); foreach ($attachment_paths as $file) { if ($file->id == $request->attachment_id) { $mimeType = Storage::mimeType('/minute/' . $file->path); $headers = [['Content-Type' => $mimeType], 'download_filename' => urlencode($file->original_filename)]; return Storage::response('/minute/' . $file->path, $file->original_filename, $headers, 'attachment'); } } } }
- 投稿日:2020-06-19T17:03:42+09:00
Vue CLI+ Laravel 5.8 で、チャット作成 firebase Cloud Messaging対応
概要
前の 、クロスドメイン構成の
Vue-CLI + Laravel 関連となり。チャット機能の作成です・会員制となり、Google認証で
ログインに対応しています。
・PWAも対応しています
・ 前のLaravel版チャットを、Vue CLIに移植した形です構成
PWA
firebase Cloud Messaging / FCM
Notification API
Vue CLI
vue-router
vue/cli-service : 4.4.0
・API サービス:
Laravel 5.8
nginx
mysql
・フロント設置ドメイン ,Vue-CLI:
netlify / ホスティングサービス
画面
・web push 受信時の、通知API で。タスクバー表示
・チャット画面、詳細
Vue components
・index
https://github.com/kuc-arc-f/vue_spa3a_4chat/blob/master/src/components/Chats/Index.vue・create
https://github.com/kuc-arc-f/vue_spa3a_4chat/blob/master/src/components/Chats/new.vue・show
https://github.com/kuc-arc-f/vue_spa3a_4chat/blob/master/src/components/Chats/show.vuepackage.json
https://github.com/kuc-arc-f/vue_spa3a_4chat/blob/master/package.json
参考のページ
https://knaka0209.hatenablog.com/entry/lara58_31cross_chat
・Vue CLI+ Laravel 5.8で、クロスドメイン SPA構成/PWA対応のCRUD作成する。
https://qiita.com/knakaqi/items/1bae7a540aa13ce8233b
- 投稿日:2020-06-19T16:11:44+09:00
vagrant コマンドがなんだか動かない時
vagrant コマンドがよくわからないエラーに悩まされるときがある。
そんな時は、xcodeのバージョンアップが影響している事がしばしば。
一旦以下のコマンドを実行して試してみる事をオススメする。
$ xcode-select --install
- 投稿日:2020-06-19T16:08:21+09:00
laravel-dump-serverのインストールでエラー
経緯
新しく用意したLaravel開発用のサーバーにおいて、そろそろdump-serverで色々dumpさせて確認しようかと思い、下記をコマンドを叩いたら
composer require --dev beyondcode/laravel-dump-serverこんなエラーが返ってきて本気っすか?ってなった話です。
Your requirements could not be resolved to an installable set of packages. Problem 1 - Installation request for beyondcode/laravel-dump-server ^1.4 -> satisfiable by beyondcode/laravel-dump-server[1.4.0]. - Conclusion: remove symfony/var-dumper v4.4.10 - Conclusion: don't install symfony/var-dumper v4.4.10 - beyondcode/laravel-dump-server 1.4.0 requires symfony/var-dumper ^5.0 -> satisfiable by symfony/var-dumper[5.0.x-dev, 5.1.x-dev, 5.2.x-dev, v5.0.0, v5.0.0-BETA1, v5.0.0-BETA2, v5.0.0-RC1, v5.0.1, v5.0.10, v5.0.2, v5.0.3, v5.0.4, v5.0.5, v5.0.6, v5.0.7, v5.0.8, v5.0.9, v5.1.0, v5.1.0-BETA1, v5.1.0-RC1, v5.1.0-RC2, v5.1.1, v5.1.2]. - Can only install one of: symfony/var-dumper[5.0.x-dev, v4.4.10]. - Can only install one of: symfony/var-dumper[5.1.x-dev, v4.4.10]. 〜省略〜 - Can only install one of: symfony/var-dumper[v5.1.1, v4.4.10]. - Can only install one of: symfony/var-dumper[v5.1.2, v4.4.10]. - Installation request for symfony/var-dumper (locked at v4.4.10) -> satisfiable by symfony/var-dumper[v4.4.10].サーバー環境の確認
エラーを見る感じsymfony/var-dumperが要因なのはなんとなく分かるのですが、
こっから何をどうすりゃいいのか?な状態。
改めて環境を確認するとphp -v PHP 7.4.5 (cli) (built: Apr 23 2020 00:10:21) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Zend OPcache v7.4.5, Copyright (c), by Zend Technologiesphp artisan --version Laravel Framework 6.18.20割と新しい目な構成。
もっと枯れたバージョンを使うしか無いんかなと諦め気味にググると下記をしろとな。
本家でissueが発行されてたのですが、laravel-dump-serverのバージョンを指定しないとダメやでって事でした。
https://github.com/beyondcode/laravel-dump-server/issues/62composer require --dev beyondcode/laravel-dump-server:1.3.0俺のdump-serverが帰ってきた。
- 投稿日:2020-06-19T13:40:38+09:00
cygwinのdockerでエラー [Failed to execute script docker-compose]
laravelを使ってlocal開発をしている時にdockerコマンドでエラーが発生するようになった。
またローカルの環境ではcygwin上で開発を行っている。╰─➤ docker-compose ps 127 ↵ [6276] Failed to execute script docker-compose Traceback (most recent call last): File "docker-compose", line 6, in <module> File "compose\cli\main.py", line 72, in main File "compose\cli\main.py", line 125, in perform_command File "compose\cli\command.py", line 47, in project_from_options File "compose\config\environment.py", line 77, in from_env_file File "compose\config\environment.py", line 72, in _initialize File "compose\config\environment.py", line 44, in env_vars_from_file File "c:\jenkins\workspace\dsg_compose_1.25.5\venv\lib\codecs.py", line 714, in __next__ File "c:\jenkins\workspace\dsg_compose_1.25.5\venv\lib\codecs.py", line 645, in __next__ File "c:\jenkins\workspace\dsg_compose_1.25.5\venv\lib\codecs.py", line 558, in readline File "c:\jenkins\workspace\dsg_compose_1.25.5\venv\lib\codecs.py", line 504, in read File "c:\jenkins\workspace\dsg_compose_1.25.5\venv\lib\encodings\utf_8_sig.py", line 117, in decode UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 10: invalid start byte色々ググってみたが、日本語を使ってるととか情報が出てくるがそもそもdocker関係を修正していないにエラーが発生するようになった。
で思いついたのがlaravelで使用している
.envをシンボリックリンクに変更したのを思い出し元に戻したら直った。。
dockerも.envを使うらしいのでcygwin環境下でのシンボリックリンクがなんかだめみたい。
- 投稿日:2020-06-19T10:27:37+09:00
AWS S3 Laravel 画像ファイルアップロード時にエラーが発生する
目的
- 画像ファイルのアップロード時にpublic指定してアップロードしたところ
実施環境
- ハードウェア環境
項目 情報 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
- ソフトウェア環境(AWS EC2 AmazonLinux2内に下記の環境を構築、構築方法はこちら→AWS EC2 AmazonLinux2だけでLaravelのアプリをデプロイする)
項目 情報 備考 AWS EC2インスタンス AmazonLinux2 こちらの方法を用いてイメージからインスタンスを作成→AWS EC2 をMacで使ってみよう! PHP 7.4.5 こちらの方法でインストール→AWS EC2 AmazonLinux2 PHPをインストールする composer 1.10.7 こちらの方法でインストール→AWS EC2 AmazonLinux2 composerをインストールする MySQL 8.0.20 for Linux on x86_64 こちらの方法でインストール→AWS EC2 AmazonLinux2 MySQLを使えるようにする 問題までの経緯
- 下記の方法にてS3に対する画像アップロード処理を実装した。
画像アップロード時の処理を下記の様に修正してpublic状態でアップロードできる様にした。
修正前
アプリ名ディレクトリ/app/Http/Controllers/ImageController.phpStorage::disk('s3')->putFile('/test', $request->file('file'));修正後
アプリ名ディレクトリ/app/Http/Controllers/ImageController.phpStorage::disk('s3')->putFile('/test', $request->file('file'), 'public');処理の動作を確認するためブラウザから画像のアップロードを行った。
問題
下記エラーが発生する。
Error executing "PutObject" on "https://S3のバケットURL/test/8iPIwmDI2VX6qOZwUq9XCJSLPGxGox2kxpfcOAkT.png"; AWS HTTP error: Client error: `PUT https://S3のバケットURL/test/8iPIwmDI2VX6qOZwUq9XCJSLPGxGox2kxpfcOAkT.png` resulted in a `403 Forbidden` response: <?xml version="1.0" encoding="UTF-8"?> <Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>5D23B7 (truncated...) AccessDenied (client): Access Denied - <?xml version="1.0" encoding="UTF-8"?> <Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>5D23B7FF0F008DAE</RequestId><HostId>PETGLYLAydwTGLlN6wskfKQpjULz1bGIQqWZc12NaJvZfCN++WYmjIFJrVoA2V8LNUK+fQwwoJk=</HostId></Error>ブラウザでのエラー画面の表示を下記に記載する。
問題解決までの経緯
- 投稿日:2020-06-19T02:24:09+09:00
Formファサード
Formファサードの記録
Form::open():HTMLフォームを作成する
Form::model():モデルをベースにしたフォームを作成する
Form::close():フォームを閉じる
Form::label():フォームのラベルを作成する
Form::input():入力フィールドを作成する
Form::text():テキスト入力フィールドを作成する
Form::password():パスワードフィールドを作成する
Form::hidden():hiddenフィールドを作成する
Form::number():数値フィールドを作成する
Form::email():メールアドレス入力フィールドを作成する
Form::url():URL入力フィールドを作成する
Form::file():ファイルアップロードのフィールドを作成する
Form::textarea():テキストエリアを作成する
Form::select():セレクトボックスを作成する
Form::selectRange():選択肢の範囲を指定してセレクトボックスを作成する
Form::selectYear():年を選択するセレクトボックスを作成する
Form::selectMonth():月を選択するセレクトボックスを作成する
Form::checkbox():チェックボックスを作成する
Form::radio():ラジオボタンを作成する
Form::reset():リセットボタンを作成する
Form::image():画像ボタンを作成する
Form::submit():Submitボタンを作成する
Form::button():ボタンを作成する
Form::getSessionStore():フォームで利用するセッションクラスを取得する
Form::token():CSRFトークンを生成する
Form::getIdAttribute():フィールド名のID属性を取得する
Form::getValueAttribute():優先度を付けた入力値を取得する
Form::old():セッションから前の入力値を取得する
Form::oldInputIsEmpty():以前の入力値が空かどうかを確認する
Form::getSelectOption():選択オプションを取得する
Form::setSessionStore():フォームで利用するセッションを設定する
- 投稿日:2020-06-19T01:04:41+09:00
Laravel掲示板に画像投稿機能を追加してみた!
paizaラーニングのLaravel入門講座で作成した掲示板に画像投稿機能を付けてみました。
画像投稿の仕組み
1.新規投稿ページからファイル選択して画像を投稿
2.storeメソッドでpublicフォルダに画像を格納。ファイルパスをデータベースに格納
3.ファイルパスを読み取り、画像を表示1.新規投稿機能を追加
新規投稿ビューにファイルアップロードのフィールドを追加する
new.blade.php<h1>MYPICTURE</h1> <p>{{$message}}</p> {{Form::open(['route'=>'picture.store','files'=>true])}} <div class="form-group"> <!--投稿した画像のユーザーネームをDBに格納させる--> {{Form::label('user_name','Name:')}} {{Form::text('user_name',null)}} </div> <div class='form-group'> <!--投稿したコメントをDBに格納するビュー--> {{Form::label('content','Content:')}} {{Form::text('content',null)}} </div> <div class='form-group'> <!--ファイルを読み込む--> {{Form::file('thefile')}} </div> <div class="form-group"> {{Form::submit('作成する',['class'=>'btn btn-primary'])}} <a href='{{ route("picture.list")}}'>一覧に戻る</a> </div> {{Form::close()}}Form::openメソッドの「'files'=>true」はファイルのアップロードを行うことを指定します。
「{{Form::file('thefile')}}」で下図のようなファイルアップロードのフォームが出来上がります。
シンボリックリンク
ビューにファイルアップロードの処理を記述したので次はコントローラ...の前に、シンボリックリンクを張りましょう。
シンボリックリンクとは、特定のファイルやディレクトリを指し示す別のファイルを作成し、それを通じて本体を参照できるようにする仕組みのことで、あるフォルダから別のフォルダに参照できるリンクを作成します。
Laravelにはこの機能が備わっており、ファイルアップロードはこの仕組みを利用します。
ディレクトリをプロジェクトの直下に移動させ、以下のコマンドをターミナルに打ち込みます。$ php artisan storage:linkすると、publicの直下に以下のようなフォルダが出来上がります。
これにより、publicからstorageフォルダにアクセスできるようになりました!2.storeメソッド
アップロードした画像をフォルダに、画像のファイル名をデータベースにそれぞれ格納するメソッドをstoreメソッドに追加します。
PictureController.php(storeメソッド)public function store(Request $request) { $picture=new picture(); //投稿した画像とコメントをDBに格納させる $picture->user_name=$request->user_name; $picture->content=$request->content; $filename=$request->file('thefile')->store('public'); //storageフォルダに投稿した画像を保存しファイルパスを格納 $picture->image=str_replace('public/','',$filename); //ファイル名から「public/」を取り除く $picture->save(); //tinkerコマンドと同じ return redirect()->route('picture.show',['id'=>$picture->id]); }アップロードした画像ファイルはstore('')関数でランダムで名前が付けられ、指定したディレクトリに保存されます。(この場合はpublic以下のフォルダに指定)
この時、デフォルトで「storage/app/」に保存され、ファイル名に「public/」と付いてしまう為、ファイル名からこれを取り除く為に一旦$filenameにファイル名を格納し、str_replace関数で「public/」を指定することで取り除いています。
あとは投稿者名やコメントと共にデータベースにファイル名を格納させます。3.ファイルパスを読み取り、画像を表示
showメソッドとビューを以下のように記述します。
showメソッド
PictureController.php(showメソッド)public function show(Request $request,$id,Picture $picture) { $message='This is your picture.'.$id; $picture=Picture::find($id); Storage::disk('local')->exists('public/storage/'.$picture->image); //$idに格納された番号と一致したデータを引っ張り出す。 return view('show',['message'=>$message,'picture'=>$picture]); }今回はローカル環境でこのアプリを作ったため、投稿した画像はローカルディスクに保存されます。
なので、「Storage::disk('local')」でローカルディスクを読み取り、「exists」に第一引数として「public/storage/」を、第二引数としてデータベースのimageカラムに格納されているファイル名をそれぞれ指定させます。ビュー
詳細ページのビューに以下の記述を追加します。
<p><img src="{{ asset('/storage/'.$picture->image)}}"></p>これでstorageフォルダ直下に格納された画像ファイルを、ファイル名ごとに表示することができました!
完成形
以上のことを踏まえて作成した画像投稿機能ですが、実際はこんな感じになります。
新規投稿画面
詳細ページ
課題
今回は「画像を投稿させ、それを表示させる。」ことを最優先にしたので、以下2つの課題があります。
保存するフォルダについて
今回は「storage/app/public」直下に画像を保存させましたが、これだとアプリを公開した際に外から画像のフォルダが丸見えになってしまいます。
ローカル環境ではまだ良いかもしれませんが、公開するとなるとセキュリティ面で非常に危険な状態なので、投稿した画像のフォルダが外から見えないようにしなければなりません。ファイルのアップロードについて
「画像をアップロードする」って言ってるくせに、実際に組んだのは「ファイルのアップロード」の機能です。
これだと、画像に限らず、テキストだろうが何だろうが「ファイル」という形の物でしたら基本的に何でもアップロードできます。
これを「画像ファイルのみ」にするには、「バリデーション」というファイルの種類を指定する処理が必要になります。以上2つ、課題として挙げた機能を今後追加していこうと思います。
まとめ
今回はLaravel掲示板に画像投稿機能を追加してみました。
正直、思い付きで「掲示板に画像を投稿出来るようにした方がよくね?」と考えて実装してみましたが、実際にやってみるとかなり難しく、時間がかかってしまいました...。
途中、teratailで質問を投げましたが、回答やアドバイスをして下さった方々に、この場を借りて御礼を申し上げます。参考文献
[Laravel] ユーザーのアイコン画像を投稿、表示させる機能の実装したのでメモ(画像の保存場所は?シンボリックリンクって?)
[Laravel]保存した画像が404エラーで表示されない
Laravel シンボリックリンクで少しハマった話
IT用語辞典 シンボリックリンク
Laravel Recipes ファイルアップロードのフィールドを作成する
Laravelで画像をアップロードする方法
- 投稿日:2020-06-19T00:44:25+09:00
【Laravel+MySQL+Docker+nginx】Laravel開発環境をDockerで構築する手順
はじめに
Laravelの勉強するための開発環境作成手順メモです。
自分用なので雑い。準備
Dockerの設定だったりしていきます。
ディレクトリ
プロジェクトディレクトリ配下に以下2つのディレクトリを作成。
- Docker
- server
docker-compose.yml
プロジェクトディレクトリ配下にdocker-compose.ymlファイルを作成。
docker-compose.ymlversion: '3' services: php: container_name: php build: ./docker/php volumes: - ./server:/var/www nginx: image: nginx container_name: nginx ports: - 80:80 volumes: - ./server:/var/www - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf depends_on: - php db: image: mysql:5.7 container_name: db environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: test_db TZ: 'Asia/Tokyo' command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci volumes: - ./docker/db/data:/var/lib/mysql - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf - ./docker/db/sql:/docker-entrypoint-initdb.d ports: - 4306:3306Dockerfile
Dockerディレクトリ配下にphpフォルダを作成。
その中にDockerfileを作成。FROM php:7.3-fpm COPY php.ini /usr/local/etc/php/ RUN apt-get update \ && apt-get install -y zlib1g-dev libzip-dev mariadb-client \ && docker-php-ext-install zip pdo_mysql #Composer install COPY --from=composer:latest /usr/bin/composer /usr/bin/composer ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer ENV PATH $PATH:/composer/vendor/bin WORKDIR /var/www RUN composer global require "laravel/installer"PHPの設定
Dockerfileと同階層でphp.iniファイルを作成。
php.ini[Date] date.timezone = "Asia/Tokyo" [mbstring] mbstring.internal_encoding = "UTF-8" mbstring.language = "Japanese"nginx
Dockerディレクトリにnginxフォルダを作成。
その中にdefault.confファイルを作成。default.confserver { listen 80; root /var/www/public; index index.php; location / { try_files $uri $uri/ /index.php$is_args$args; } location ~ \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; } }MySQL
Dockerディレクトリにdbフォルダを作成。
その中にmy.cnfファイルを作成。my.cnf[mysqld] character-set-server=utf8mb4 collation-server=utf8mb4_unicode_ci [client] default-character-set=utf8mb4Laravelプロジェクト
プロジェクトのルートディレクトリに移動。
以下コマンドを実行。docker-compose up -d docker-compose exec php bash laravel new確認
locallhostで画面が表示されれば成功。
やったね。DB設定
dockerで開発環境を作った場合、.envファイルとdocker-compose.ymlファイルの情報を合わせとかないとmigrateできなかったりとめんどくさいので今やっとく。
DB_CONNECTION=mysql DB_HOST=db DB_PORT=3306 DB_DATABASE=test_db DB_USERNAME=root DB_PASSWORD=rootこれでDBの登録も問題なし。
まとめ
自分用メモなのでめちゃくちゃざっくりしてますが参考になれば。
- 投稿日:2020-06-19T00:19:10+09:00
【Laravel】Laravel最低限の基礎メモ
経緯
ずっとRailsをしてたのですが、ありがたいことにPHPメインの自社開発企業に就職できたので現在PHPを勉強しています。
ただMVCの仕組みだったりあんなにRailsで頑張って覚えたのに、私の記憶が頼りないせいで忘れてしまいそうなので、考えが似た感じのPHPフレームワークLaravelで定着させようと思い勉強し始めました。
まだめっちゃ基礎の段階ですが、とりあえず復習のために色々メモします。
Laravel
PHPのフレームワーク。
多分今PHPのフレームワーク=Laravelみたいになってる。まだ初歩なので何とも言えませんが、今のところRailsと似てるので割と理解しやすい印象です。
デバックツール
composer require barryvdh/laravel-debugbarartisan
Railsコマンド的なやつ。
Serverディレクトリで実行します。php artisan ~~~Model
Model名は単数形。
作成
php artisan make:model Models/nameマイグレーションファイルとコントローラーも同時に作成する場合
php artisan make:model Models/name -mcマイグレーションファイルだけ一緒に作りたい場合
php artisan make:model Models/name -mMigration
テーブル作成の履歴的な。
Migration名は複数形。作成
php artisan make:migration create_names_tableDatabaseフォルダに作成される。
カラム追加は公式参照。
https://readouble.com/laravel/5.5/ja/migrations.html
追加したらMigrateする。php artisan migrateカラムを追加したいとき
php artisan make:migration add_カラム名_to_カラムを追加したいテーブル名_table —table=カラムを追加したいテーブル名->after('後ろに挿入したい既存カラム名');Controller
いろんな処理するところ。
作成
php artisan make:controller コントローラー名記述
class内にpublicでメソッドを作成。
***Controller.phpreturn view(‘viewのフォルダ名.表示させたいファイル名’);View
ファイル名には必ず「***.blade.php」とつける。
Route
記述
web.phpRoute::get(‘表示したいViewのフォルダ名/表示したいファイル名’,’コントローラー名@メソッド名’);ルート一覧書き出し
php artisan route:list > ファイル名.textファサード
get,select,where,groupbyなどSQLに近い構文。
***Controller.phpDB::table(テーブル名)->get();クエリビルダ
***Controller.phpuse Illuminate\Support\Facades\DB; //Controllerに貼り付けLaravel UI
jsやsassを入れる。
ログイン・新規登録機能などをつける。【参考】
https://www.techpit.jp/courses/laravel6-aws/lectures/13324326メッセージの日本語化
下記ファイルをlangフォルダにコピー。
https://github.com/minoryorg/laravel-resources-lang-jaconfig/app.phpのlocationがjaになってるか確認。
まとめ
公式見るのがぶっちゃけ一番早い。
Railsと違ってわかりやすかったのでとりあえず困ったら公式でまず検索かけるのが良いと思いました。あくまでメモなので随時追加していくと思います。











