- 投稿日:2020-11-08T23:49:10+09:00
配列とオブジェクトの違いについて
結論
配列
とオブジェクト
では、簡単に言うと書き方
と呼び出し方
が違います。配列 ( 連想配列 )
配列
=keyとvalueがセット
。
[ ]
で配列を宣言
し、key
とvalue
を=>(ダブルアロー演算子)
で結ぶ。
呼び出しは、$array['key'];
をecho
で表示させる。$array = [ //配列$arrayを宣言 "name" => "ワタナベ", //name(key)にワタナベ(value)を代入 "number" => 1, ]; ↓ 呼び出し echo $array['name']; //ワタナベが表示される。オブジェクト
オブジェクト
=クラスの中にプロパティを宣言
。
{}
でクラスの宣言
をし、new演算子
でインスタンス化
をして値を持たせる。
new演算子
=インスタンスを作成する演算子
。
インスタンス化
=オブジェクトを作ること
。
呼び出しは、->(シングルアロー演算子)
でプロパティを指定
。class Kazoku { //クラス名:1文字目は大文字 public $name; //プロパティ:クラス内で使える変数を定義 public $age; function __construct($name, $age){ //コンストラクター:プロパティに引数を代入 $this -> name = $name; // nameプロパティ($this->name)に、渡ってきた引数($name)を代入している $this -> age = $age; } } $kazoku1 = new Kazoku("佐藤", "20"); //new演算子でインスタンス化(オブジェクト$kazoku1を作成) ↓ 呼び出し echo $kazoku1 -> name; // $kazoku1の中にあるname(佐藤)が表示される。メリット
配列
・データの追加や削除が容易
に行える。
オブジェクト
・プロパティと共にメソッドを設定
できる。
数百の関数の中から目的の関数を探すのは大変です。
しかし、オブジェクトであれば関数はクラスに紐づいている
ため、対象のクラスから容易にアクセスや修正
が行えます。参考元はこちら
(https://coinbaby8.com/different-between-object-and-array.html)
(https://webukatu.com/wordpress/blog/4839/#i-2)
(https://qiita.com/riotam/items/cb5406daa9a1c6a694da)
- 投稿日:2020-11-08T22:46:36+09:00
【Lumen】.envをconfig()で読み込む
はじめに
Laravelでは、
.env
から環境変数を読み込む際、env()
が使われます。ただし、この
env()
で直接.env
にアクセスするのは好ましくありません。理由としては、Laravelは設定ファイルのキャッシュが存在する場合、
.env
を読み込まずにキャッシュを参照する仕様になっているためです。ではどうすればいいのかというと、タイトルにある通り、
config()
を使用します。本記事では、この
config()
での.env
読み込みについて、
Lumenで実装する方法についてまとめます。※Laravelでの具体的な実装例や
env()
を使ってはいけない理由などをブログに詳しくまとめられている方がいらっしゃいます。
本記事では詳細には触れないので、気になる方はこちらをご覧ください。
Laravel の .env の値は config() 経由で使うLumenでconfig()を使う
config
ディレクトリ配下に任意の名前のファイルを作成します。config/hoge.php<?php return [ 'fuga' => env('FUGA') ];ここでは、
.env
にあるFUGA
という環境変数を登録することにします。
bootstrap/app.php
に以下のコードを追記bootstrap/app.php// 追記 $app->configure('hoge');ここがLaravelとは違ってLumen独自の設定となります。
configure()
の引数には、上で作成したファイル名を入れます。(今回は'hoge'
)設定は以上です。
あとは環境変数を呼び出したいところで、以下のように呼び出せます。config('hoge.fuga');おわりに
Lumenを触ることになって間もないですが、やはりLaravelとは違う部分が所々に見られて、
戸惑うことが多いですね...
- 投稿日:2020-11-08T22:43:10+09:00
Warning: Invalid argument supplied for foreach()の対処法
エラー内容
Invalid argument supplied for foreach()
= PHPのforeach文
で配列データ
を取り出そうとした場合に、配列のデータが入っていない時
に出るエラー。
foreach文
=配列の要素がある分だけ繰り返し処理
をするループ文。解決方法
まずは、
配列データが入っているかを判定
する必要があります。
foreach文
で使えるのは配列
とオブジェクト
のみなので、(arry)
を使用して変数を強制的に配列に
してあげることで対処できます。配列とオブジェクトについては別の記事に投稿します。
foreach($stmt as $row){ //処理内容 } ↓ foreach((array)$stmt as $row){ //処理内容 }参考元はこちら
(https://memocarilog.info/wordpress/5132)
(https://qiita.com/takuma-jpn/items/678876ad12b9ae9998ac)
- 投稿日:2020-11-08T22:02:01+09:00
DataTables+生PHP+MySQL のサイト構築例
本社オンプレ経由で情報を支社からも参照できる簡易ポータルを、生のPHPで書いてみた。
<table>
タグでリスト表示しているページがあるなら、DataTablesにちょっと書き替えるだけで、それっぽいWebアプリケーションにリニューアルできるという一例。環境
種類 内容 オペレーティングシステム Ubuntu 18.04 Webサーバ Apache 2.4 リレーショナルデータベース MySQL 5.7 プログラミング言語 PHP 7.2 フロントエンドフレームワーク DataTables, Bootstrap4, jQuery, FontAwesome Web Appsフレームワーク なし システム構成図
アプリケーション画面
Bootstrap対応したDataTablesを使用。
インクリメンタルサーチ、ページネーション、ソート機能が、面倒な作り込み無しに実装できている。
ソースコードもシェアするので参考になれば!
データベース接続パラメータ、SQL文、Font Awesome のKitコードを埋めればそのまま動くはず。Code<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <meta name="author" content="MindWood"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <title>取引先検索</title> <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.21/css/dataTables.bootstrap4.min.css" /> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> <style> main { padding: 80px 10px 40px; } .fixed-bottom { color: #eee; background-color: #163; } </style> <script src="https://kit.fontawesome.com/<your kit code>.js" crossorigin="anonymous"></script> </head> <body> <nav class="navbar fixed-top navbar-expand-sm navbar-dark bg-primary"> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarToggler1" aria-controls="navbarToggler1" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarToggler1"> <a class="navbar-brand" href="#">XXXXXX情報ポータル</a> <ul class="navbar-nav mr-auto mt-2 mt-lg-0"> <li class="nav-item active"> <a class="nav-link" href="#"><i class="fas fa-search fa-fw"></i>取引先検索</a> </li> <li class="nav-item"> <a class="nav-link" href="sns.php"><i class="fab fa-twitter fa-fw"></i>SNS連携</a> </li> </ul> <a href="logout.php" class="btn btn-light my-2 my-sm-0"><i class="fas fa-sign-out-alt"></i> ログアウト</a> </div> </nav> <?php define('DB_NAME', '<your database name>'); define('DB_USER', '<your database user>'); define('DB_PASS', '<your database password>'); $link = mysqli_connect('localhost', DB_USER, DB_PASS) or die('DBMS接続エラー'); mysqli_select_db($link, DB_NAME) or die('DB選択エラー'); $result = mysqli_query($link, " SELECT xxxxx as contract_id, xxxxx as contract_date, ... FROM xxxxx a LEFT JOIN xxxxx b ON a.xxxxx = b.xxxxx ORDER BY a.xxxxx; ") or die('クエリ実行エラー'); ?> <main role="main"> <table class="table table-striped" id="customer_list"> <thead> <tr> <th>受託番号</td> <th>受託日</td> <th>企業名</td> <th>担当者名</td> <th>電話番号</td> <th>メールアドレス</td> <th data-toggle="tooltip" title="XXXXシステムの照会区分コードに準じる">照会区分</td> <th>照会内容</td> <th data-toggle="tooltip" title="当社担当エリア">担当支社</td> </tr> </thead> <?php while ($row = mysqli_fetch_array($result)) { ?> <tr> <td><?= $row['contract_id'] ?></td> <td><?= $row['contract_date'] ?></td> <td><?= $row['company_name'] ?></td> <td><?= $row['staff_name'] ?></td> <td><?= $row['phone_number'] ?></td> <td><?= $row['email'] ?></td> <td><?= $row['inquiry_code'] ?></td> <td><?= $row['inquiry_body'] ?></td> <td><?= $row['branch_office'] ?></td> </tr> <?php } ?> </table> </main> <footer class="fixed-bottom text-center"> <small>Copyright © by MindWood</small> </footer> <script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> <script type="text/javascript" src="https://cdn.datatables.net/1.10.21/js/jquery.dataTables.min.js"></script> <script type="text/javascript" src="https://cdn.datatables.net/1.10.21/js/dataTables.bootstrap4.min.js"></script> <script type="text/javascript"> // DataTablesの日本語化 $("#customer_list").DataTable({ destroy: true, language: { url: "https://cdn.datatables.net/plug-ins/3cfcc339e89/i18n/Japanese.json" } }); // Bootstrapツールチップの初期化 $('[data-toggle="tooltip"]').tooltip(); </script> </body> </html> <?php mysqli_close($link); ?>
- 投稿日:2020-11-08T19:40:19+09:00
composer のバージョンをアップデートする
アップデートコマンド
最新バージョンにアップデート (今だとバージョン 2.x へ)
composer self-updateバージョンを指定してアップデート (1.10.17 を指定する場合)
composer self-update 1.10.17Command-line interface / Commands - Composer
エラーが発生する場合
下記のようなエラーが発生する場合
SHA384 is not supported by your openssl extension, could not verify the phar file integritycomposer のバージョンが古すぎるため、コマンドで更新できません。再インストールが必要です。
公式ドキュメント通りにインストールしていれば、同じように。
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" php -r "if (hash_file('sha384', 'composer-setup.php') === 'c31c1e292ad7be5f49291169c0ac8f683499edddcfd4e42232982d0fd193004208a58ff6f353fde0012d35fdd72bc394') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" php composer-setup.php php -r "unlink('composer-setup.php');"Mac/Linux であれば下記のように
composer.phar
をグローバルで使えるように。mv composer.phar /usr/local/bin/composerインストールできたか確認する。
$ composer -v ______ / ____/___ ____ ___ ____ ____ ________ _____ / / / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/ / /___/ /_/ / / / / / / /_/ / /_/ (__ ) __/ / \____/\____/_/ /_/ /_/ .___/\____/____/\___/_/ /_/ Composer version 2.x.x
- 投稿日:2020-11-08T19:27:05+09:00
kubernetes上にLaravel環境を構築した際のメモ
前回記事の続きとなる。
kubernetes上に作成したLNMP環境に対してLaravelプロジェクトをデプロイした際のメモ。
Laravelプロジェクトの構築
今回、構築作業にヒューマンオペレーションが入り込むのを極力避けることを目的とし、Laravelプロジェクト作成をコンテナログインからのコマンド実行以外で実施することとした。
Laravelプロジェクトの初期化
Pod作成時に
command
から実施してしまうと、Pod起動の度にプロジェクトの作成がされてしまう。ということで、Laravelプロジェクトの初期化限定で、Jobオブジェクトを利用することにした。
Jobの作成
Job
は、コンテナを利用し処理を実行するリソースである。Jobにて作成されたコンテナは、マニフェストファイルに記載されているタスク完了後、削除される。
今回は1回限りのタスクを実行するので、
completions(成功回数):1/parallelism(並列度):1/backoffLimit(失敗許容回数):0
とする。また、今回、
spec.ttlSecondsAfterFinished: 30
とし、Laravelプロジェクト作成後、30sでPodを削除するようにする。これを利用し、phpポッドの利用するPVに対してLaravelプロジェクトのデプロイのみ行う。
apiVersion: batch/v1 kind: Job metadata: name: laravel-init-job labels: app: lnmp spec: # One Shot Task completions: 1 parallelism: 1 backoffLimit: 0 # 実行後30sでJob実行Podを削除 ttlSecondsAfterFinished: 30 template: metadata: labels: app: lnmp spec: containers: - name: laravel-init image: laravel imagePullPolicy: IfNotPresent # laravelプロジェクトの初期構築 command: - sh - -c args: - "composer create-project --prefer-dist laravel/laravel '' \ && chmod 777 -R ./storage/ \ && chmod 777 -R ./bootstrap/" volumeMounts: - name: php-persistent-storage mountPath: /var/www restartPolicy: Never volumes: - name: php-persistent-storage persistentVolumeClaim: claimName: php-server-pv-claim上記
Job
マニフェストファイルlaravel-init-job.yaml
をデプロイ。$ kubectl apply -f laravel-init-job.yamlJob実行時の不具合
Job実行時に以下のエラーとなった。
Creating a "laravel/laravel" project at "./" Installing laravel/laravel (v8.1.0) As there is no 'unzip' command installed zip files are being unpacked using the PHP zip extension. This may cause invalid reports of corrupted archives. Besides, any UNIX permissions (e.g. executable) defined in the archives will be lost. Installing 'unzip' may remediate them. - Installing laravel/laravel (v8.1.0): Downloading (100%) Created project in /var/www/public > @php -r "file_exists('.env') || copy('.env.example', '.env');" Loading composer repositories with package information Updating dependencies (including require-dev) Killedなんか
killed
となり、インストールに失敗している。当然Laravelプロジェクトは作成されていない。こちらの記事([PHP] composer install が killed で失敗するときの原因と対処)にドンピシャで答えが載っていた。
どうやらメモリが足らないのが原因だったらしい。今回、phpのデプロイメントにはメモリ制限は設けていないので、ホストのメモリがそもそも足りていないと思われる。
ということでminikubeサーバーのメモリを
2.5G
から4.0G
へ増やし、マウントしていたボリュームphp-persistent-storage
内のファイルを削除。再びJobを実行することでLaravelの作成に成功した。
Jobを実行したPodが削除されない
spec.ttlSecondsAfterFinished: 30
としたにも関わらず、Jobを実行したPodがstatus: terminating
のまま残り続けた。調べてみると、こちらの記事(Kubernetes で Complete/Failed となった Job を自動削除する)にて説明がされていた。
どうやら
TTLAfterFinished
は、フィーチャーゲートなる実験的機能であるらしい。ということで、以下コマンドから
minikube
を起動し、機能を有効化する。(kubernetes > v1.12以上である必要がある。)$ minikube start --feature-gates=TTLAfterFinished=trueこの状態でJobを実行することで、Podがコマンド終了後に削除されるようになった。
Laravel環境変数ファイル(.env)をConfigMap化
mysql-phpポッド間の通信をサービス経由で実行するにあたり、Laravelの
.env
ファイルにサービス名を指定する必要がある。そこで、
.env
をConfigMap
とし、コンテナ外部から設定できるようにする。.envの修正
こちらの記事(docker-composeでLaravelの開発環境を整える方法とその解説)を参考にし、
.env
の以下箇所を修正DB_CONNECTION=mysql # mysql-php間の通信で利用するService名 DB_HOST=lnmp-mysql-service DB_PORT=3306 DB_DATABASE=test_db DB_USERNAME=user DB_PASSWORD=passwordConfigMapの作成
以下コマンドを実行し、ConfigMap
laravel-env
を作成する。$ kubectl create configmap laravel-env --from-file={ホスト上の.envの配置されているパス}ConfigMapをマウント
phpのDeploymentに作成したConfigMapをマウントし、再度読み込む。
この際、以前作成したボリュームと、ConfigMapのマウントパスが被ってしまいエラーとなった。
そこで、こちらの記事(KubernetesのConfigMapを使ってWordpressのphp.iniを書き換える)を参照し、マウント先を
subPath
を使用してファイル自体へと変更。apiVersion: apps/v1 kind: Deployment metadata: name: lnmp-php-deployment labels: app: lnmp spec: replicas: 1 selector: matchLabels: app: lnmp template: metadata: labels: app: lnmp spec: containers: - name: lnmp-php-deployment image: laravel imagePullPolicy: IfNotPresent ports: - containerPort: 9000 volumeMounts: - name: php-persistent-storage mountPath: /var/www - name: laravel-env mountPath: /var/www/.env # マウント先をファイル自体へと変更する。 subPath: .env volumes: # サーバーログ出力先(nginxと共有) - name: php-persistent-storage persistentVolumeClaim: claimName: php-server-pv-claim # laravel .envをinject - name: laravel-env configMap: name: laravel-env items: - key: .env path: .env mode: 0644その後、Deploymentの作成を実施した。
mysqlの初期化
dbの初期化を実施。これはphpポッド内でコマンドを実行して行った。(極力手作業を避けたいとはなんだったのか……?)
$ php artisan migrate
Migration table created successfully.
というメッセージが表示され、php-mysqlポッド間の通信設定が正常に設定できていることが確認できた。Laravelプロジェクトへのアクセス
これでLaravel環境に必要な物が一通り揃ったはずなので、アクセスしてみる。
以下コマンドを実行し、nginxのホスト上のポートを確認しアクセス。
[root@kube ~]# kubectl describe service/lnmp-nginx-service | grep NodePort Type: NodePort NodePort: <unset> 32626/TCPLaravel初期画面が出た!!
(地味にLaravelがブラウザのダークテーマに対応しているのに驚いた。)
まとめ
Job
を利用し、Laravelプロジェクトの初期化を実施することができた。今回は
Job
の実行タスクをプロジェクトの初期化のみとしたが、これをGithub
から取得するタスクに変更したりすることで、実装環境の均等化を図ったりできるんだろか?でもそうなれば、
Job
の管理が大変になるような気もする。どうやっているんだろう?
- 投稿日:2020-11-08T19:09:48+09:00
LaravelとjQueryで非同期処理で実装するいいね機能を世界一わかりやすく解説してみたい
やりたいこと
ジャズライブの口コミを投稿できるサイトをチームで制作しています。
今回は、ユーザーの投稿にいいねをできる機能を実装したいです。結構苦労したので、初心者だけど、いや初心者だからこそ日本一わかりやすくメモを残しておきたいと思います。ご指摘などありましたら、ぜひ容赦無くよろしくお願いします。Laravel 7です。
仕様
- ハートボタンとカウンターで構成する
- 各投稿が合計いくつのいいねを集めているかが表示される
- 下記行動ができるのはログインしているユーザーのみ
- いいねボタンが押されたらスタイルをピンクにし、いいねカウントの数字を1増やす
- もう一度押されたらスタイルと数字を元に戻す
- あるユーザーが1つの投稿に対していいねが押せるのは1回のみ
- 自分がいいねした投稿は常にピンクになっている
実装前のプログラムの挙動に関する疑問...
- どの時点でサーバー側にリクエストを出せばいい?(非同期処理だとしたら、イベントが発生した直後?)
- 非同期処理だとしたら、何回も押されたらその都度リクエストを出してサーバーと通信するのか??
- 誰がリクエストを出す?(JavaScriptのEventListener?)
- どんなリクエストを出せばいい?(review_id, いいね押されたよっていう何らかのサイン...でもどんな??)
- 投稿が削除されたら、それに付されたいいねもDBから全て削除する(リレーションで設定可能)
こんなこともわからない状態からでもなんとか実装に至りました!
材料
僕はお恥ずかしながら、まずどんな材料が必要なのか?そこから想像するのが難しかったです。
で、結局はこんなのが必要でした↓
材料 View これは誰でもわかりますよね。 CSS いいねされたハートマークは色を変えたいところです。 Frontのスクリプト この辺は僕でも、サイトを動的にするには必要だってわかりました。非同期処理はajaxでjQueryがそれできると知っていたので、jQueryを採用。 DB いいね専用のテーブルを作ります。ある投稿がいくついいねを集めているかカウントするために必要です。今回はEloquentでModelを作成しusersとreviewsと1対多でリレーションする。 migration DBバージョン管理ファイルで、各開発環境でテーブルの自動生成をしてくれます。 Model 今回はEloquentを利用します。ModelはDBテーブルの内容を定義したり操作するクラスです。 Route ルートも要るんですね。ページが遷移しない機能は初めてで、ページが遷移しなくてもルートって要るんだ!と知りました...。 Controller コントローラも要るんですね。でも確かにコントローラなきゃ誰がDBと通信するの?て話ですよね。 では、実際にどう料理するか見てきましょう!
実装!
DB データベース設計
テーブル構造(必要なフィールドのみ抜粋)
users id created_at, updated_at reviews id created_at, updated_at user_id likes id created_at, updated_at user_id review_idusersとreviewsが既に作成済という前提で、likesテーブルとリレーションを作っていきましょう。
ターミナルで下記コマンドで、モデルを生成します。-m
もしくは--migration
オプションでマイグレーションファイルも同時に作成できます。$php artisan make:model Like -mMigration マイグレーション
DBのバージョン管理機能、マイグレーションファイルで、先のテーブル構造を作っていきます。
database/migrations/yyyy_mm_dd_xxxxxx_create_likes_table.phpclass CreateLikesTable extends Migration { public function up() { Schema::create('likes', function (Blueprint $table) { $table->id(); //bigIncrements('id')と同じ $table->timestamps(); //s複数形でcreated_atとupdated_atを生成 $table->foreignId('user_id') //usersテーブルの外部キー設定 ->constrained() //userテーブルのidカラムを参照するconstrainedメソッド ->onDelete('cascade'); //削除時のオプション $table->foreignId('review_id') //同じことをreviewsテーブルとも ->constrained() ->onDelete('cascade'); }); }マイグレーションファイルが準備できたら、マイグレートを実行します↓
terminal$php artisan migrate
Model モデル
app/Like.php<?php namespace App; use Illuminate\Database\Eloquent\Model; class Like extends Model { public function user() { //usersテーブルとのリレーションを定義するuserメソッド return $this->belongsTo(User::class); } public function review() { //reviewsテーブルとのリレーションを定義するreviewメソッド return $this->belongsTo(Review::class); } }
- belongsToの中身User::class。
::
はスコープ定義演算子。static、定数、オーバーライドされたクラスのプロパティやメソッドにアクセスできる。::class
はclassキーワードと呼ばれ、クラスの完全修飾名を文字列で取得できる。つまり'App\Model名'
が返ってくる。つまり'App\Model名'をパラメータにするのと同じことです。(むしろそれが今は標準?)view ビュー
ビューを作る前に仕様の再確認です。
いいねをできるのはログインユーザーのみ。なので、①ログインユーザーと②ゲストでの条件分岐が必要。
さらに自分が一度いいねした投稿は、いつ来てもピンクなままでないとわからなくなってしまうので、①の中でもいいね済の投稿とそうでない投稿を条件分岐しないとなりません。
まとめると、3つの条件分岐が必要になります→(①-1 ログインユーザーでいいねの押されていない投稿、①-2 ログインユーザーでいいねの既に押された投稿、② ゲストユーザー)<!-- head内 --> <meta name="csrf-token" content="{{ csrf_token() }}"> <!-- body内 --> <!-- 参考:$itemにはReviewControllerから渡した投稿のレコード$itemsをforeachで展開してます --> @auth @if (!App\Like::where('user_id', Auth::user()->id)->where('review_id', $item->id)->first()) <span class="likes"> <i class="fas fa-music like-toggle" data-review-id="{{ $item->id }}"></i> <span class="like-counter">{{$item->likes_count}}</span> </span><!-- /.likes --> @else <span class="likes"> <i class="fas fa-music heart like-toggle liked" data-review-id="{{ $item->id }}"></i> <span class="like-counter">{{$item->likes_count}}</span> </span><!-- /.likes --> @endif @endauth @guest <span class="likes"> <i class="fas fa-music heart"></i> <span class="like-counter">{{$item->likes_count}}</span> </span><!-- /.likes --> @endguest
- auth, endauth, guest, endguestは認証ディレクティブと呼ばれるbladeの機能で、アクセスしているユーザがログインしているのかゲストかを判別できます。
- iタグはfont-awesomeです。(音楽サイトなので、ハートではなく♫を使ってます)
- 巷にはなぜかaタグを使用するコーディング例が多いですが不要です。aタグを入れると余計なページ遷移が起きるので、逆にうざかったのですが、aタグを使うメリットをぜひ教えてください。
- iタグのdata-の属性はカスタムデータ属性と呼ばれるグローバル属性(HTMLのどのタグにも設定可能な属性)の一種。これを介して、HTMLとJavaScript、jQuery間などでデータをやりとりできます。ここではいいねをする対象の投稿のid(review_id)をjQueryに伝える役割を担います。
CSS
いいねマークにlikedクラスが付いた時のスタイルを適宜設定します。
styles.css.liked { color: pink; }jQuery
like.js$(function () { let like = $('.like-toggle'); //like-toggleのついたiタグを取得し代入。 let likeReviewId; //変数を宣言(なんでここで?) like.on('click', function () { //onはイベントハンドラー let $this = $(this); //this=イベントの発火した要素=iタグを代入 likeReviewId = $this.data('review-id'); //iタグに仕込んだdata-review-idの値を取得 //ajax処理スタート $.ajax({ headers: { //HTTPヘッダ情報をヘッダ名と値のマップで記述 'X-CSRF-TOKEN' : $('meta[name="csrf-token"]').attr('content') }, //↑name属性がcsrf-tokenのmetaタグのcontent属性の値を取得 url: '/like', //通信先アドレスで、このURLをあとでルートで設定します method: 'POST', //HTTPメソッドの種別を指定します。1.9.0以前の場合はtype:を使用。 data: { //サーバーに送信するデータ 'review_id': likeReviewId //いいねされた投稿のidを送る }, }) //通信成功した時の処理 .done(function (data) { $this.toggleClass('liked'); //likedクラスのON/OFF切り替え。 $this.next('.like-counter').html(data.review_likes_count); }) //通信失敗した時の処理 .fail(function () { console.log('fail'); }); }); });
$()
はjQueryのセレクターの書き方。$はjQueryの略です。- thisは変数の一種で、特殊な変数。プログラムが自動的に値を代入するもの。今回はイベントが発火した変数like=iタグが代入されています。
- なぜ
$this
と$
が付くのか?jQueryにおいて、変数を宣言する際、$
はjQueryオブジェクト(=$()
でセレクトした要素)を入れるための変数宣言で、 $は必須ではないが、通常の変数と区別するのに通常使います。- .onはイベントハンドラー。第一パラメータにイベントの種類、第二パラメータにハンドラとして無名関数を取っています。
- .dataはjQueryのメソッド。HTML内に仕込んだカスタムdata属性の値を取得することができます。ここでは投稿のid(review_id)を受け取ります。
取得したい要素.data('カスタムdata属性の名前')
という文法になります。- $.ajax()は、非同期処理を行うイベントハンドラ。$.はこれまたjQueryのこと。中のパラメータはコード内の説明ご参照。ここの大きな構文は、
$.ajax().done().fail()
です。通信に成功したら、doneメソッドを、失敗したらfailメソッドを実行します。- attr()は、attributeの略で日本語訳すると「属性」です。つまり、なんてことはない、指定された属性の値を取ってくるメソッドです。(日本人プログラマの不利なところは一回英単語の意味を知らないといけないとこだなと最近思ってます)
- .next()は、セレクター。Sibling(兄弟)の後ろの要素を全て、つまり全ての弟を返します。その中から特定の要素を指定する場合は、パラメータで指定します。
- obj.html(htmlString)は、obj(=英語でいうところの目的語)にhtmlStringをセットします。.done()のパラメータdataにはコントローラからreview_likes_countという名前の「新規いいね後の総いいね数」が(←あとでコントローラで見ていきましょう)、
{review_likes_count : 1}
というJSONの形で渡ってきます。それをdata.review_likes_countとい文法でプロパティにアクセスします。JavaScriptの記法では「変数名.プロパティ名(=key)」でそのオブジェクトの対応する値が取得できます。この.をドット演算子と呼びます。このサイトがわかりやすいです。- .fail()には、処理が失敗したときの指示をコールバック関数で書いておきます。コールバック関数とは、他の関数(ここではfail)に引数として渡される関数です。ここでは、単純にconsoleに'fail'という文字列をログを出力するというだけの実装にしています。
Route ルート
routes/web.phpRoute::post('/like', 'ReviewController@like')->name('reviews.like');Ajaxで指定したurlと整合性を取ります。
Controller コントローラ(いいねをする/撤回する)
LikeControllerを作った方が良かったのかもしれませんが、私は投稿を制御するReviewController.phpに作りました。
app/Http/ReviewContollerpublic function like(Request $request) { $user_id = Auth::user()->id; //1.ログインユーザーのid取得 $review_id = $request->review_id; //2.投稿idの取得 $already_liked = Like::where('user_id', $user_id)->where('review_id', $review_id)->first(); //3. if (!$already_liked) { //もしこのユーザーがこの投稿にまだいいねしてなかったら $like = new Like; //4.Likeクラスのインスタンスを作成 $like->review_id = $review_id; //Likeインスタンスにreview_id,user_idをセット $like->user_id = $user_id; $like->save(); } else { //もしこのユーザーがこの投稿に既にいいねしてたらdelete Like::where('review_id', $review_id)->where('user_id', $user_id)->delete(); } //5.この投稿の最新の総いいね数を取得 $review_likes_count = Review::withCount('likes')->findOrFail($review_id)->likes_count; $param = [ 'review_likes_count' => $review_likes_count, ]; return response()->json($param); //6.JSONデータをjQueryに返す }
- Authクラスに対してuserメソッドでログインしているユーザーのモデルインスタンスを返す。
- 投稿のidが、ビューのカスタムdata属性→jQuery Ajax経由で$requestで渡ってきているので、それをキャッチします。
- このユーザーがこの投稿に既にいいねをしていれば、そのlikeレコードを取得します。
- モデルから新しいレコードをDBに挿入するには、まず新しいインスタンス(記入用紙)を準備して、save()メソッドで実行します。いいねの新規レコードをDBに挿入する準備として、newキーワードでLikeクラスのインスタンスを生成しておきます。参考→公式ドキュメント「クラスの基礎」
- 投稿テーブルを管理するReviewモデルに対してwithCountメソッドを使用することでリレーションされている別テーブルの数をカウントすることができます。今回はパラメータにいいねテーブルとのリレーション名likesを渡すことで、いいねの数を数えます。投稿idをキーにしています。likes_countはwithCountメソッドとセットの関係にあります。Laravelでは、
withCount('hoge')
とすると自動的にhoge_count
というフィールドが生成されるのです。参考→関連するモデルのカウント- jQueryの
.done(data)
に$paramという変数名で最新の総いいね数を返します。Controller コントローラ(いいね数をindexに表示する)
いいねをする、撤回するの機能は以上ですが、次回index.blade.phpに訪問したときに、いいね数を返してあげないといけません。
ReviewController.phppublic function index(Request $request) { $items = Review::withCount('likes')->orderBy('id', 'desc')->paginate(10); $param = [ 'items' => $items, ]; return view('reviews.index', $param); }
- withCount()は先ほど説明した通りです。これをitemsでビューに返して、ビューは
{{$items->likes_count}}
で投稿ごとにいいね数を取得、表示することができます。- orderBy()は指定した順番でレコードを取得するメソッド。第一パラメータは並べ替えの基準となるフィールドを選択、第二パラメータはソートする方法(昇順asc=小さい順、降順desc=大きい順)を指定します。
- paginateはレコードが多い場合に、1ページごとの表示数を指定するメソッドです。
実装は以上になります。
エラーと対処の例
私が直面したエラーを参考にメモしておきます。
responseJSON: {message: "CSRF token mismatch.", responseText: "{↵ "message": "CSRF token mismatch.",
<meta name="csrf-token" content="{{ csrf_token() }}">
をビューのheadタグに追記して解決responseJSON: {message: "Unauthenticated."} status: 401 statusText: "Unauthorized"
responseJSON: message:"Property [likes_count] does not exist on the Eloquent builder instance."
→なんだったっけ...すみません。忘れました。思い出したら追記します。あとがき
自分が実装したことをきちんと理解したく、あやふやなところを全て言語化しました。もしご指摘などあれば、ぜひコメントください。
Thanks to:
【jQuery】$(this)の意味&使い方について
- 投稿日:2020-11-08T18:45:56+09:00
laravel migration失敗した話
migrationに失敗してエラーが出たので、解決策を共有します。
やりたかったことは、usersテーブルの追加です。
なので、下記コマンドを実行しました。php artisan make:migration create_users_table //users table 作成エラー内容
どうやら、未定義の定数だそうです。
ErrorException Use of undefined constant JSON_INVALID_UTF8_SUBSTITUTE - assumed 'JSON_INVALID_UTF8_SUBSTITUTE'ネットで検索してみると、PHPのバージョンに関する問題でした。
PHP7.2以降じゃないと出るエラーだとか
バージョンを確認するとPHP7.1でした。そもそも、dockerコンテナ外でmigrationしてました。
ってことで、dockerコンテナの中へPHPのバージョンは7.4でした
そして、
migrationも無事通りました!!
- 投稿日:2020-11-08T18:04:44+09:00
Laravelでmigrationファイル作る時、複数形にしていいの?だめなの?
Laravelでmigrationファイルを作るとき、デフォルトの設定では「スネークケースで複数形で書くと、キャメルケースで単数形に変換される」ってなってる。
例えば
・create_users_table.phpという名前でmigrationファイル作成→usersというテーブル作成、modelはUsers.phpで作成する。
・create_user_books_table.phpという名前でmigrationファイル作成→user_booksというテーブルを作成、modelはuserBooks.phpで作成する。じゃあ、「data」ってテーブル作りたいとき、どうなるの?dataって、複数形ないよね?「information」は?「news」なんて、元々複数形だけど?
もちろん$tableとかを使って自力で明示的に名前つければ悩むことはないんだけど、せっかくだったら自動的に解釈してほしいじゃないさ。
そんな時、「この単語って複数形で設定するの?」というのを確認する方法がありました。ありがとうございますLaravel の 複数形を事前に調べる
artisanでtinkerを立ち上げて、「echo Str::plural('調べたい単語');」ってすると、複数形か単数形のままか表示してくれる。
> php artisan tinkerってやってtinker立ち上げて、
>>> echo Str::plural('book');って打ってenterすると、
booksと返ってきます。
ちなみに
data → data
information → information
news → newsこれでもう迷わない!
- 投稿日:2020-11-08T17:08:59+09:00
DockerでLaravel開発環境構築(Mac)
■構成
docker-laravel
├ docker-compose.yml
├ docker
│ ├ php
│ │ ├ php.ini
│ │ └ Dockerfile
│ └ nginx
│ └ default.conf
└ server■手順
1.Dockerのデスクトップアプリをダウンロード
公式サイトより手順に従いダウンロード(簡単です)
https://www.docker.com/products/docker-desktop2.Docker.appを起動
terminalopen /Applications/Docker.app3.ディレクトリ作成
docker-laravelという作業用フォルダ(名称は任意)をデスクトップに用意し、
その中に上記構成でフォルダ、ファイルを配置します。
※面倒であれば以下より、git cloneを。
https://github.com/masayan1126/docker-laravel4.主要ファイル
詳細は割愛します(githubを参照ください。)
・docker-compose.yml
・Dockerfile
・php.ini
・default.conf(nginx設定ファイル)5.Dockerを起動してlaravelプロジェクトを作成
・dockerを起動(少し時間かかります)
docker-compose.ymlがあるディレクトリで実行$ docker-compose up -d・phpコンテナに入る
$ docker-compose exec php bash・Laravelプロジェクト作成
・下記コマンド後にserverディレクトリ以下にLaravelプロジェクトが構築される。
root@ae5eec7aea3c:/var/www#$ composer create-project laravel/laravel docker-laravel-app(プロジェクト名)・localhostへアクセスし、laravelのトップ画面を確認できれば成功。
6.ついでにmysqlも
・mysqlコンテナに入り、ログインできれば接続完了。
terminal$ docker exec -it db-host-practice bashterminalmysql -u docker -p Enter password: パスワード・.envファイルを修正(docker-compose.ymlの内容に合わせる)
.envDB_CONNECTION=mysql DB_HOST=db-host-practice DB_PORT=3306 DB_DATABASE=[docker-composeで定義したデータベース名] DB_USERNAME=[docker-composeで定義したユーザ名] DB_PASSWORD=[docker-composeで定義したパスワード名]・マイグレーション
root@4ef799d9efc8:/var/www/docker-laravel-app#php artisan migrate※うまくいかなければ、以下を試す。
・php artisan cache:clear
- 投稿日:2020-11-08T14:36:00+09:00
laravel-enum:v2の日本語化
laravel-enumのv2の日本語化の書き方が他の記事と違ったので備忘録的に書き残す
環境
% sw_vers ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H2 % docker version Client: Docker Engine - Community Cloud integration: 1.0.1 Version: 19.03.13 API version: 1.40 # php -v PHP 7.4.7 (cli) (built: Jun 11 2020 18:41:17) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies with Xdebug v2.9.6, Copyright (c) 2002-2020, by Derick Rethans # php artisan -v Laravel Framework 7.26.1 # mysql --version mysql Ver 14.14 Distrib 5.7.30, for Linux (x86_64) using EditLine wrappercomposer require bensampo/laravel-enum:2.2
最初何も考えずに
composer require bensampo/laravel-enum
叩いたら「最新のlaravel-enumはlaravel7.に対応してない」と怒られた
公式docによるとlaravel7.に対応してるのはbensampo/laravel-enum:2.2
らしいのでバージョン指定でcomposer requireする
公式doc読むの大事ほんとcomposer require bensampo/laravel-enum:2.2
ここからはv2のdocを参照する
enum定義
enumファイル作成
php artisan make:enum UserType
enum定義
UserType.phpuse BenSampo\Enum\Enum; use BenSampo\Enum\Contracts\LocalizedEnum; final class UserType extends Enum implements LocalizedEnum { const Administrator = 1; const SuperAdministrator = 2; }ちなみにmysqlのenum型は0を''として予約されているので1から定義する
日本語化
多言語化のインターフェースを有効にする
# php artisan vendor:publish --provider="BenSampo\Enum\EnumServiceProvider" Copied Directory [/vendor/bensampo/laravel-enum/resources/lang] To [/resources/lang/vendor/laravelEnum] Publishing complete.
resouces/ja
配下にenums.phpを作成して定義resources/lang/ja/enums.php<?php use App\Enums\UserType; return [ UserType::class => [ UserType::Administrator => '管理者', UserType::SuperAdministrator => 'スーパー管理者', ], ];これで日本語化されます
- 投稿日:2020-11-08T14:12:00+09:00
【PHPの名前空間について】
version5.4以降に使える名前空間についてメモっとく
namespace A; class A{ public static function xxx(){} } namespace B; class A{ public static function yyy(){} }この場合namespaceAのAクラスと、namespaceBのAクラスということになる。
呼び出すときはuseキーワードを使う。use A\Aこの場合、これ以下でAクラスを呼び出したときはnamespaceAのAクラスのことを参照していることになる。
use A\Bこうすることで、namespaceAのBクラスを呼び出していることになる。
別名で呼び出す場合
use A\A as C
こうするとこれ以下で、C::xxx();としたとき、実施にはnamaspaceAのAクラスを参照していることになる。use A\A as C C::xxx(); //A::xxx();と同義【namespaceを使う際はグローバルクラスなのかそのnamespace内のクラスなのかを意識する】
例えば、以下だとエラーになる。namespace A try{ //エラー構文 }catch(Exception $e){ echo $e->getMessage(); }なぜなら、ここでいうExceptionクラスはnamespaceA内のものを指しているから。
\Exceptionこうしないとエラーメッセージの入ったグローバルなExceptionクラスにアクセスしていないことになる。
- 投稿日:2020-11-08T13:46:32+09:00
【PHP】timestamp形式の日付時刻をフォーマットして表示したい
やりたいこと
現在作成中のアプリで記事投稿日の表示フォーマットを変更したい
投稿一覧画面のソース抜粋
<!-- 投稿一覧画面 --> <div class="container"> <div class="contents"> <?php foreach($posts_arr as $key => $value) :?> <div class="card" style="margin-top: 16px;"> <div class="card-header" style="padding: 0; font-family: serif;"> <div class="text-center" style="margin-top: 0.6rem; line-height: 0rem;"> <a><i class="fas fa-fish"></i> <?php echo $posts_arr[$key]['fish_kind']; ?></a> </div> <div class="text-right" style="margin-right: 0.6rem;"> <a style="font-size: 0.6rem;">投稿者 <span style="font-size: 0.8rem; font-weight: bold;"><?php echo $posts_arr[$key]['nickname']; ?></span>さん</span></a> </div> </div> <div class="card-main" style="object-fit: contain; margin-bottom: 16px;"> <img src="./img/<?php echo $posts_arr[$key]['file_name']; ?>" class="card-img"> </div> <div class="card-body"> <p class="card-text" style="margin-bottom: 0.4rem;"><?php echo mb_strimwidth($posts_arr[$key]['angler_comment'], 0, 200, '…', 'UTF-8'); ?></p> <div class="text-right"> <a style="font-size: small;">投稿日: <?php echo $posts_arr[$key]['created_at']; ?></a> </div> <div class="text-right"> <a href="./posts/show.php?p_id=<?php echo $posts_arr[$key]['id']; ?>" class="card-link" style="font-size: small;">詳細を見る</a> </div> </div> </div> <?php endforeach; ?> </div> </div>改修内容
投稿日: 2020-11-05 21:42:08
表示の秒数部分を無くして
投稿日: 2020-11-05 21:42
にしたい改修方法
// 日付表示部分 <div class="text-right"> <?php $date = new DateTime($posts_arr[$key]['created_at']);?> <a style="font-size: small;">投稿日: <?php echo $date->format('Y-m-d H:i'); ?></a> </div>関数一つ通せばできるものかなと考えながら調べている内にdate_format()を発見
しかし、date_format()はそもそもオブジェクトありきの関数だったため
フォーマットする前にオブジェクトを生成してから実行する必要があると知った。
結論、echoの前にtimestamp形式のデータをオブジェクト生成してからフォーマットする流れでできた。
<?php echo date_format($date, 'Y-m-d H:i'); ?>もちろんechoの部分はこれでもいけますがなるべくオブジェクト指向の記述で書きたいので
前者の方を採用しました。や↑ったぜ
参考
- 投稿日:2020-11-08T10:53:39+09:00
array_splice()ってなんやねん!!
array_splice()ってなんやねん
説明
array_shift() - 配列の先頭の要素を取り除く
ただそれだけ、$tehai_predict = [1,2,3,4,5,6,7,8,9,11,12,13]; $lead_element = array_shift($tehai12_predict); var_dump($tehai_predict); var_dump($lead_element);[2,3,4,5,6,7,8,9,11,12,13] 1が出力される。
筆者
2020年1月ごろからプログラミング学習し始めました。
日々の学習についてあげています。
麻雀点数計算アプリを作成中!!!
- 投稿日:2020-11-08T10:51:21+09:00
array_shift()ってなんやねん!!
array_shift()ってなんやねん
説明
array_shift() - 配列の先頭の要素を取り除く
ただそれだけ、$tehai_predict = [1,2,3,4,5,6,7,8,9,11,12,13]; $lead_element = array_shift($tehai12_predict); var_dump($tehai_predict); var_dump($lead_element);[2,3,4,5,6,7,8,9,11,12,13] 1が出力される。
筆者
2020年1月ごろからプログラミング学習し始めました。
日々の学習についてあげています。
麻雀点数計算アプリを作成中!!!
- 投稿日:2020-11-08T08:25:01+09:00
Laravel ローカルに画像をアップロードし表示する
ode# 目次
- Macのローカルで作成した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.8 Homebrewを用いてこちらの方法で導入→Mac HomebrewでPHPをインストールする Laravel バージョン 6.X commposerを用いてこちらの方法で導入→Mac Laravelの環境構築を行う MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いてこちらの方法で導入→Mac HomebrewでMySQLをインストールする 前提条件
- 下記記事の作業が実行できていること
前提情報
- 本記事はMacのローカルで作成されたLaravelアプリから
アプリ名ディレクトリ/storage/app/public/images
にファイルをアップロードする機能を作る。アプリ名ディレクトリ/storage/app/public/images
にアップロードされたファイルを表示するページと画像の詳細ページと画像表示ページを作成する。下記に作成するページのURLを記載する。(画像表示ページとは画像をブラウザ内の全画面で表示するページのことを指す)
- 一覧ページののURL
/output
- 詳細ページのURL
/detail/imagesテーブルのid
- 表示ページのURL
/display/imagesテーブルのid
- 本記事の作業完了したソースは下記にアップしてある。
概要
- ルーティングファイルの記載
- コントローラファイルの記載
- ビューファイルの作成と記載
- 確認
詳細
- 下記の説明で実行するコマンドはすべてMacのローカルのターミナルで実行するものとし、実行場所はアプリ名ディレクトリであるlaravel6_imageディレクトリとする。
ルーティングファイルの記載(本作業完了後のソースコードはこちら→https://github.com/miriwo0104/laravel6_image/tree/image_display_local/01_route)
- 下記コマンドを実行してルーティングファイルを開く。
terminal $ vi routes/web.php
下記のルーティング情報を記載する。
laravel6_image/routes/web.php// 画像一覧ページ用 Route::get('/output', 'ImageController@output')->name('output'); // 画像詳細ページ用 Route::get('/detail/{images_id}', 'ImageController@detail')->name('detail'); // 画像表示ページ用 Route::get('/display/{image_id}', 'ImageController@display')->name('display');記載後のルーティングファイルの全内容を下記に記載する。
laravel6_image/routes/web.php<?php /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | contains the "web" middleware group. Now create something great! | */ Route::get('/', function () { return view('welcome'); }); // 画像アップロードページ用 Route::get('/input', 'ImageController@input')->name('input'); // 画像アップロード処理用 Route::post('/upload', 'ImageController@upload')->name('upload'); // 下記を追記する // 画像一覧ページ用 Route::get('/output', 'ImageController@output')->name('output'); // 画像詳細ページ用 Route::get('/detail/{images_id}', 'ImageController@detail')->name('detail'); // 画像表示ページ用 Route::get('/display/{image_id}', 'ImageController@display')->name('display'); // 上記までを追記するコントローラファイルの記載(本作業完了後のソースコードはこちら→https://github.com/miriwo0104/laravel6_image/tree/image_display_local/02_controller)
下記コマンドを実行して作成したコントローラファイルを開く。
$ vi app/Http/Controllers/ImageController.php下記のようにコントローラファイルの内容を追記修正する。追記修正後のコントローラファイルの全体の内容を下記に記載する。
laravel6_image/app/Http/Controllers/ImageController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Image; use Illuminate\Support\Facades\Storage; class ImageController extends Controller { public function input() { return view('images/input'); } public function upload(Request $request) { $this->validate($request, [ 'file' => [ // 空でないこと 'required', // アップロードされたファイルであること 'file', // 画像ファイルであること 'image', // MIMEタイプを指定 'mimes:jpeg,png', ] ]); if ($request->file('file')->isValid([])) { $file_name = $request->file('file')->getClientOriginalName(); // オリジナルファイルのファイル名の取得 $file_path = Storage::putFile('/images', $request->file('file'), 'public'); // ファイルのアップロードとアップロードパスの取得 $image_info = new Image(); $image_info->file_path = $file_path; $image_info->file_name = $file_name; $image_info->save(); return redirect('/'); }else{ return redirect(route('input')); } } // 下記を追記する public function output() { $image_infos = Image::select('*')->get(); return view('images.output', ['image_infos' => $image_infos]); } public function detail($image_id) { $image_info = Image::find($image_id); return view('images.detail', ['image_info' => $image_info]); } public function display($image_id) { $image_info = Image::find($image_id); return view('images.display', ['image_info' => $image_info]); } // 上記までを追記する }ビューファイルの作成と記載(本作業完了後のソースコードはこちら→https://github.com/miriwo0104/laravel6_image/tree/image_display_local/03_view)
下記コマンドを実行してビューファイルを作成して開く。
$ vi resources/views/images/output.blade.php下記の内容をビューファイルに記載する。
laravel6_image/resources/views/images/input.blade.php<h1>アップロードされた画像一覧</h1> @foreach ($image_infos as $image_info) <hr> <img src="{{asset('storage/' . $image_info['file_path'])}}" alt="{{asset('storage/' . $image_info['file_path'])}}"> <br> <a href="{{route('detail', ['images_id' => $image_info['id']])}}"> <button type="submit">詳細</button> </a> <br> <a href="{{route('display', ['images_id' => $image_info['id']])}}"> <button type="submit">表示</button> </a> @endforeach下記コマンドを実行してビューファイルを作成して開く。
$ vi resources/views/images/detail.blade.php下記の内容をビューファイルに記載する。
laravel6_image/resources/views/images/detail.blade.php<h1>画像の詳細</h1> <img src="{{asset('storage/' . $image_info['file_path'])}}" alt="{{asset('storage/' . $image_info['file_path'])}}"> <br> <a href="{{route('display', ['images_id' => $image_info['id']])}}"> <button type="submit">表示</button> </a> <ul> <li>ID: {{$image_info['id']}}</li> <li>アップロード日: {{$image_info['created_at']}}</li> </ul>確認
下記コマンドを実行してローカルサーバを起動する。
$ php artisan serve下記にアクセスする。
登録してある画像が表示されることを確認する。
画像下部の「詳細」をクリックする。
画像の詳細情報が表示されることを確認する。
画像下部の「表示」をクリックする。
画像のみがブラウザで表示されることを確認する。
参考文献
- 投稿日:2020-11-08T01:48:19+09:00
prepare関数について
prepareとは?
prepare
=SQL文の基本部分が同じで値だけ異なる
ような場合(例えば同じテーブルに値だけ変えて何回もデータを挿入するような場合)に効率よく行える機能を提供
。prepareの他に似たメソッドとしてqueryがあります。
違いは、
query
:変動値がない場合に使用
$pdo->query('SELECT * FROM user');
prepare
:変動値がある場合に使用
(prepare、bindValue、executeを使う)$stmt = $pdo->prepare("SELECT * FROM user WHERE name=:name"); $stmt->bindValue(':name', $name, PDO::PARAM_STR); $stmt->execute();参考元はこちら
(https://blog.senseshare.jp/query-prepare.html#index1)
(https://www.javadrive.jp/php/pdo/index8.html)
- 投稿日:2020-11-08T00:16:54+09:00
Laravel MAMPの設定からmigrateまでの手順
環境
・Laravel 6.19.1
・MAMP 5.7MAMPをインストールし、Webブラウザを立ち上げる
MAMPをインストールし、起動する。
MAMPインストールページ起動後、「⌘ + ,」を入力し、Preferenceを立ち上げる。
Portsタブを選択し、「Apache Port」と「Nginx Port」を80、「MySQL Port」を3306に変更する。
OKを選択し、次はMAMPの「Start Servers」をクリックする。
サーバーが立ち上がると、MAMPのWebページトップに遷移する。
「TOOLS」タブを選択し、「PHPMYADMIN」を選択する。データーベース設定を行う
ここから本題のデーターベース設定に移っていく。
まずはデフォルトでは英語の設定になっているので、日本語に設定を行う。
次に左のサイドメニューから「新規作成」をクリックし、データーベースを作成していく。
データーベース名を入力し、「作成」をクリックすると、先ほど入力したデーターベース名で新規作成される。データベース ユーザーの作成
先程作成したデーターベースを選択し、タブの「特権」を選択する。
下に「ユーザーアカウントを追加する」とあるので、クリックする。
ログイン情報の設定を行う画面に遷移するので、「ユーザー名」と「パスワード」を任意で設定し、
ホスト名を「%」→「localhost」に変更する。
ページの下の方にいくと、「Check all」とあるので、チェックを入れる。
右下の「実行」をクリックすると、ユーザーが新規作成される。
改めて新規作成したデータベースを選択 -> 「特権」をクリックし、作成したユーザーが表示されていればOK。
MySQL側の設定はこれで完了。Laravel データベース設定
VSCodeなどのエディタを使い、環境設定ファイル(.envファイル)を開く。
画像に基づき、必要な情報を入力していく。database.phpの設定。
次に、データベース設定ファイル( config > database.php )を開く。
46行目あたりから、mysqlの設定が記載されているので移動してください。'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => true, 'engine' => null, ],デフォルトでは
'unix_socket' => env('DB_SOCKET', ''),
となっているのでここを'unix_socket' => '/Applications/MAMP/tmp/mysql/mysql.sock',に変更する。
この設定を行わないと、$ php artisan migrate
コマンドを入力した際にエラーが発生する。(下記参照)[PDOException]SQLSTATE[HY000] [2002] No such file or directoryphp artisan migrate 実行
ここまでの手順を踏み、ターミナルでmigrateコマンドを入力する。
$ php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_18_19_000000_create_failed_jobs_tableこのような表示がされれば上手くいっています。
念のため、MAMPのWebページに戻り、新規作成したデーターベースを確認してみましょう。
このように、テーブルが3つ作成されていれば問題ないです。
今回は以上になります。
- 投稿日:2020-11-08T00:16:54+09:00
Laravel MAMPの設定からmigrateまでの手順 [忘備録]
環境
・PHP 7.4.9
・Laravel 6.19.1
・MAMP 5.7MAMPをインストールし、Webブラウザを立ち上げる
MAMPをインストールし、起動する。
MAMPインストールページ起動後、「⌘ + ,」を入力し、Preferenceを立ち上げる。
Portsタブを選択し、「Apache Port」と「Nginx Port」を80、「MySQL Port」を3306に変更する。
OKを選択し、次はMAMPの「Start Servers」をクリックする。
サーバーが立ち上がると、MAMPのWebページトップに遷移する。
「TOOLS」タブを選択し、「PHPMYADMIN」を選択する。データーベース設定を行う
ここから本題のデーターベース設定に移っていく。
まずはデフォルトでは英語の設定になっているので、日本語に設定を行う。
次に左のサイドメニューから「新規作成」をクリックし、データーベースを作成していく。
データーベース名を入力し、「作成」をクリックする。
入力したデーターベース名で、左サイドメニューに新規作成されていれば上手くいってます。
次はデーターベースユーザーの作成を行っていきます。データベース ユーザーの作成
先程作成したデーターベースを選択し、画面右上に表示されているタブの「特権」を選択する。
下に「ユーザーアカウントを追加する」とあるので、クリックする。
ログイン情報の設定を行う画面に遷移するので、「ユーザー名」と「パスワード」を任意で設定し、
ホスト名を「%」→「localhost」に変更する。
ページの下の方にいくと、「Check all」とあるので、チェックを入れる。
右下の「実行」をクリックすると、ユーザーが新規作成される。
改めて新規作成したデータベースを選択 -> 「特権」をクリックし、作成したユーザーが表示されていればOK。
MySQL側の設定はこれで完了。Laravel データベース設定
VSCodeなどのエディタを使い、環境設定ファイル(.envファイル)を開く。
画像に基づき、必要な情報を入力していく。(下記参考例)DB_CONNECTION=mysql DB_HOST=localhost DB_PORT=3306 DB_DATABASE=test DB_USERNAME=test_user DB_PASSWORD=test12345database.phpの設定。
次に、データベース設定ファイル( config > database.php )を開く。
46行目あたりから、mysqlの設定が記載されているので移動してください。'mysql' => [ 'driver' => 'mysql', 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'strict' => true, 'engine' => null, ],デフォルトでは
'unix_socket' => env('DB_SOCKET', ''),
となっているのでここを'unix_socket' => '/Applications/MAMP/tmp/mysql/mysql.sock',に変更する。
この設定を行わないと、$ php artisan migrate
コマンドを入力した際にエラーが発生する。(下記参照)[PDOException]SQLSTATE[HY000] [2002] No such file or directoryphp artisan migrate 実行
ここまでの手順を踏み、ターミナルでmigrateコマンドを入力する。
$ php artisan migrate Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table Migrating: 2019_08_19_000000_create_failed_jobs_table Migrated: 2019_18_19_000000_create_failed_jobs_tableこのような表示がされれば上手くいっています。
念のため、MAMPのWebページに戻り、新規作成したデーターベースを確認してみましょう。
このように、テーブルが3つ作成されていれば問題ないです。
今回は以上になります。
- 投稿日:2020-11-08T00:01:15+09:00
サニタイズ / エスケープについて
サニタイズとは?
サニタイズ
=危険なコードやデータを変換または除去して無力化
する処理。例えば、Webサイトに設置された入力フォームなどから、悪意のあるコードが入力され、その文字列が実行されることで様々な被害に遭う可能性があります。
サニタイズ
の一種にエスケープ
というものがあり、
大抵はサニタイズ
=エスケープ
として捉えている事がほとんどです。エスケープとは?
エスケープ
=特殊な文字を無害な文字に強制的に置き換える
処理。
PHPでは< > ' " &
などの文字を変数値としてそのまま使用することができますが、これをHTMLにそのまま出力すると、HTMLタグなどの特殊文字として解釈されてしまいます。
なのでエスケープ処理することにより被害防止をすることが出来ます。例えばHTMLだと、エスケープ処理することで下記のように勝手に特殊文字を変換してくれます。
表示 エスケープ > < < > " " ' ' <?php $html = '<h2>エスケープについて</h2>'; ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>サニタイズについて</title> </head> <body> <h1>サニタイズについて</h1> <?php echo $html; ?> </body> </html> ↓ ブラウザ表示 サニタイズについて //HTMLは問題なし。 <h2>エスケープについて</h2> // PHPは <h2> も表示されてしまう。これではJavaScriptなどで悪質なコードを入力されてしまうと、勝手にアラートを鳴らされたり、ブラウザの中にある個人情報を勝手に取得して外部に送信されてしまうなどの恐れが出てきます。
対策方法は、例えばPHPには専用関数でhtmlspecialchars()があります。
JavaScriptやSQLでの対策方法については参考元リンクよりご覧ください。参考元はこちら
エスケープ(https://qiita.com/n_hirai/items/df0a21d2409ee47973e5)
対策方法(https://webukatu.com/wordpress/blog/1635/#i)