20210118のPHPに関する記事は16件です。

PHPとjqueryでJSON形式ではないAjax通信をする

先輩エンジニアさんから教えていただいたjson形式ではないAjax通信を行います。
html/jqueryは以下の通り。

<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script>
            $(function() {
                $('#ajax_post').click(function () {
                    var hogeValue = $('#hoge').val();
                    var someValue = $('#some').val();
                    $.ajax({
                        url: 'ajaxTest.php',
                        type: 'post',
                        data: "hoge="+hogeValue+"&some="+someValue
                    }).done(function(data){
                        /* 通信成功時 */
                        $('#ajax_show').text(data);
                    }).fail(function(data){
                        /* 通信失敗時 */
                        alert('通信失敗!');          
                    });
                });
            });
        </script>
    </head>
    <body>
        <input type="text" id="hoge"><br>
        <input type="text" id="some"><br>
        <input type="button" id="ajax_post" value="送信">
        <p id="ajax_show"></p>
    </body>
</html>

json形式にするのって結構めんどくさいですよね。
いちいちjson形式にするほど大量のデータをやり取りしないときにいいと思います。
データベースとやり取りするときは結局Json形式で値は返ってきますが。
続いてphp。

<?php

    $afterHoge = $_POST["hoge"];
    $afterSome = $_POST["some"];
    $afterWord = "";

    $afterHoge .= '形式ではない';
    $afterSome .= '通信成功!';
    $afterWord = $afterHoge . $afterSome;
    echo $afterWord;!

これで簡単にフォームの値のやり取りを行います。

スクリーンショット 2021-01-18 22.09.07.png

送信ボタンを押すと…

スクリーンショット 2021-01-18 22.12.49.png

ちゃんとphpを通って返ってきました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

谷藤賢一『いきなりはじめるPHPワクワク・ドキドキの入門教室』でPHPを勉強してみた(1)

仕事のため、PHPの勉強を始めた。

タイトル通り、私が勉強に使っているのは谷藤賢一『いきなりはじめるPHPワクワク・ドキドキの入門教室』だが買ってはいけない本を買った気がする……

この本では、学習を進めるためにXAMPP(ザンプ)というサーバーをダウンロードするよう書かれているが、この記事を書いている2021年1月時点でテキスト通りにいかないことがいくつかある。

ポートのチェックの設定変更ができない

XAMPPをダウンロードしたとき、パソコンにSkypeが入っている場合、ポートを奪い合ってXAMPPが起動しない。そのために本書では「Skypeの設定で、ポートのチェックを外してください」と書いてあるのだが、現在、Skypeの設定画面からポートのチェックを外すことはできない。インターネットを検索すればなんとかポートの変更はできるが、初学者向けの本でこれはどうかと思う。

テキスト通りにやってもエラーが出る

テキストに書いてあることをただやってるだけなのに、

「Server error!
サーバ内部で障害が発生し、 リクエストに応えることができませんでした。 サーバが過負荷であるか、 CGI スクリプトにエラーがあります。
サーバーの障害と思われる場合は、ウェブ管理者までご連絡ください。
Error 500
localhost
Apache/2.4.23 (Win32) OpenSSL/1.0.2h PHP/5.6.24」

というエラーが出る。

ヤフー知恵袋でも、私と同じところで躓いた人がいた。

「新しいテキストを買ったほうがいいんじゃないか……」と思ったが、【PHP】超優良入門書『いきなりはじめるPHP』をMAMPで完走するために知っておくべき5つのこと【Mac】
というサイトによると、MAMPをダウンロードすれば学習を進められるらしいのでMAMPをダウンロードした。

今日はChapter3 ワクワク!プログラミング編の3-1から3-8まで進めた。

■追記
MANPをダウンロードし起動したあと、スタートを押してもstop serversにならず、接続できない場合は、Preferenes → PHPのタグを押し、「Standard Version」の初期設定がを7.3.7から、7.2.14 に変更すればいい。

HTML 4.01だからdoctype宣言が長い。

段落を
でなく
と書いてるテキストはじめてみた。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel6 + Vue.js + Laravel SanctumのSPA認証でのアクセス制限の簡単な実装。

自分用なのでざっくりと。
時間がある時にもっと詳しい記事を書きたい。

例えばdashboardページへ未認証ユーザーがアクセスしようとするとログインページへリダイレクトさせたい場合。

routes/api.php
Route::middleware('auth:sanctum')->get('/authenticated', function () {
    return 'authenticated';
});
resources/js/app.js
import VueRouter from 'vue-router';
import DashBoard from "./components/DashBoard";
import LoginComponent from "./components/LoginComponent";

//〜略〜

const router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/login',
            name: 'login',
            component: LoginComponent,
        },
        {
            path: '/dashboard',
            name: 'dashboard',
            component: DashBoard,
            beforeEnter: (to, from, next) => {
                axios.get('/api/authenticated')
                    .then((res) => {
                        if (res.data == 'authenticated') {
                            next();
                        }
                    }).catch(() => {
                        next({ name: 'login' });
                    });
            },
        },
    ]
});

//〜略〜

このようにすれば良い。

おまけ

最初は、

routes/api.php
Route::middleware('auth:sanctum')->get('/authenticated', function () {
    return true;
});
resources/js/app.js
import VueRouter from 'vue-router';
import DashBoard from "./components/DashBoard";
import LoginComponent from "./components/LoginComponent";

//〜略〜

const router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/login',
            name: 'login',
            component: LoginComponent,
        },
        {
            path: '/dashboard',
            name: 'dashboard',
            component: DashBoard,
            beforeEnter: (to, from, next) => {
                axios.get('/api/authenticated')
                    .then(() => {
                        next();
                    }).catch(() => {
                        next({ name: 'login' });
                    });
            },
        },
    ]
});

//〜略〜

ってやってみて、実際にログインしてdashboardページにアクセスしようとしたら、

The Response content must be a string or object implementing __toString(), \"boolean\" given.

っていう「booleanじゃだめよ!」っていうエラーが出てうまくいかなかったんだよねえ。。

でもとある外国人のYouTube動画ではこのやり方でうまくいってたんだよねえ。。

どうしてなんだろう。
まだまだ勉強不足みたいです。。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】 Sass(Scss)の使い方実例。Laravel Mixを使ってコンパイルする。

Laravel Mixというツールを使うとSassをCSSにコンパイルすることができる。

出力先のディレクトリ設定も超簡単。

目次

  1. Laravel Mixの機能
  2. Node.jsとnpmのインストール
  3. Laravel Mixのインストール
  4. コンパイル先の指定
  5. ファイルの作成
  6. コンパイルの実行
  7. ブラウザに表示
  8. 変更反映の自動化
  9. 本番用のコンパイル
  10. URLの自動変換機能(オフにする方法も)
  11. 複数ファイルをワイルドカードで指定する


Laravel Mixの機能

SassをCSSにコンパイルするだけでなく、Less, Stylus, PostCSSにも対応している。複数のcssファイルを1つのcssファイルに統合することもできる。

また、CSS以外にもJSの圧縮、.vue(ビューJS)、.jsx(リアクトJS)などのコンパイルにも対応している。

今回は、Sass -> CSS機能のみにフォーカス。


コンパイル手順

1. Node.jsとnpmのインストール

node -v 
#v12.18.3

npm -v
#6.14.8

バージョンが表示されればインストール済み。
ない場合は、node.js公式ページからダウンロード。


2. Laravel Mixのインストール

Laravelのプロジェクトを作成した時点でルートディレクトリ直下にpackage.jsonが存在する。

ここにはnodeの依存パッケージが記述されており、以下コマンドで記載のパッケージをインストールする。

$npm install



package-lock.jsonが作成されたらインストール完了。このファイルはインストール済みのnpmパッケージが記載されている。(自動生成されるファイルなので編集しない!)

image.png
laravel mixもインストールされている。

$npm install [パッケージ名]で指定したパッケージをインストールする。
パッケージ名を指定しない場合は、package.jsonに従ってインストールを行う。


3. コンパイル先の指定

デフォルトでルートディレクトリにwebpack.mix.jsがある。この中にコンパイルする形式や出力先の情報を記述する。

mix.メソッド名('コンパイルするファイルパス', '出力先');

webpack.mix.js(デフォルト)
const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js')
    .postCss('resources/css/app.css', 'public/css', [
        //
    ]);

↓ 以下に変更

webpack.mix.js
mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/app.scss', 'public/css');

resources > sass の app.scssファイルをコンパイルして、public > css 配下に出力する。



▼(補足)別の指定方法
メソッドチェーンでつなげず、別々に記述しても機能する。

php
mix.js('resources/js/app.js', 'public/js');
mix.sass('resources/sass/app.scss', 'public/css');


4. ファイルの作成

実際にコンパイルするファイルを作成する。

app.scssファイルの作成

resources > sass > app.scss

app.scss
h1 {
  color: skyblue;
}

テストなのでシンプルに、、

image.png

ビュー

resorces > views > for-scss.blade.php

for-scss.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="{{ asset('css/app.css') }}">
</head>
<body>
  <div>
    <h1>SCSSのテスト</h1>
  </div>
</body>
</html>

▼cssファイルの読み込み
コンパイルされたcssファイルを読み込む記述を記載する。

<link rel="stylesheet" href="{{ asset('css/app.css') }}">

URLの呼び出しはassetヘルパー関数を使用。

(参考)assetヘルパー関数とは?


ルーティング

routes > web.php

web.php
Route::get('scss', function () {
    return view('for-scss');
});


5. コンパイルの実行

以下コマンドでコンパイルが開始する。

npm run dev



▼実行例

$ npm run dev

99% done plugins BuildOutputPlugin

   Laravel Mix v6.0.10   

✔ Compiled Successfully in 1143ms
┌───────────────────────────────────────────────────────┬──────────┐
│                                                  File │ Size     │
├───────────────────────────────────────────────────────┼──────────┤
│                                            /js/app.js │ 596 KiB  │
│                                           css/app.css │ 25 bytes │
└───────────────────────────────────────────────────────┴──────────┘

webpack.mix.jsの指示通り、jsファイルとcssファイルが作成される。
image.png

コンパイル結果の確認

生成されたapp.cssを確認する。今回はapp.scssと同じ内容が記述されていればOK。

app.css
h1 {
  color: skyblue;
}


6. ブラウザに表示

サーバーを起動する。

php artisan serve



URLを入力。http://127.0.0.1:8000/scss

image.png

狙い通りコンパイル後のCSSが反映されている。


7. 変更反映の自動化

$ npm run watchを実行すると、指定したコンパイル元のファイルに変更があった場合に、自動でコンパイルを実行する。

$ npm run watch

> @ watch /Users/s01386/projects/laravel/test-pj
> mix watch



ctrl + cでサーバーを停止すれば自動監視(mix watch)も停止する。


8. 本番用のコンパイル

$npm run productionを実行すると、本番用の圧縮したファイルを出力してくれる。

圧縮版は、改行やスペース、コメントアウトなどを削除したもの。

$ npm run production

> @ production /Users/s01386/projects/laravel/test-pj
> mix --production

99% done plugins BuildOutputPlugin



   Laravel Mix v6.0.10   


✔ Compiled Successfully in 5416ms
┌───────────────────────────────────────────────────────┬──────────┐
│                                                  File │ Size     │
├───────────────────────────────────────────────────────┼──────────┤
│                                            /js/app.js │ 84.8 KiB │
│                                           css/app.css │ 14 bytes │
└───────────────────────────────────────────────────────┴──────────┘

▼出力されたファイル

app.css
h1{color:red}

改行やスペースが削除されている。


9. URLの自動変換機能(オフにする方法も)

Laravel Mixの便利機能の一つで、urlで画像リソースを指定した場合に、対象のファイルをpublic/imagesフォルダにコピーし、コンパイル後のURLをコピー後のファイルのパスに変更する機能がある。

▼例

css
.example {
  background: url('../../public/img/cat3.png');
}

↓ コンパイル

$ npm run dev

99% done plugins BuildOutputPlugin

   Laravel Mix v6.0.10   

✔ Compiled Successfully in 888ms
┌──────────────────────────────────────────────────────┬───────────┐
│                                                 File │ Size      │
├──────────────────────────────────────────────────────┼───────────┤
│                                           /js/app.js │ 596 KiB   │
│                                          css/app.css │ 105 bytes │
│     images/cat3.png?204c4068c53d4775b6e9cb23998276cb │ 158 KiB   │
└──────────────────────────────────────────────────────┴───────────┘

image.png

▼コンパイル後のCSSファイル

css
.example {
  background: url(/images/cat3.png?204c4068c53d4775b6e9cb23998276cb);
}

画像がパラメータで指定されている。(画像名にパラメータはついていない)

自動コピー&URL変換機能をオフにする

この機能をオフにして、指定したURLをそのままコンパイルしたい場合は、webpack.mix.js内にオプションメソッドで以下を追記する。

webpack.mix.js
.options({
      processCssUrls: false
   });



▼実際のコード例

webpack.mix.js
 mix.sass('resources/sass/app.scss', 'public/css').options({
    processCssUrls: false
 });


10. 複数ファイルをワイルドカードで指定する

scssファイルがいくつもある場合、コンパイル元のファイルと出力先を個別に設定するのは手間。

npmのパッケージの一つであるglobを使うことでファイルをワイルドカードで指定できる。

const mix = require('laravel-mix');
const glob = require('glob');

glob.sync('resources/sass/*.scss').map(function(file) {
  mix.sass(file, 'public/css');
});

・冒頭にconst glob = require('glob');を記述。



▼scssファイルが多いPJ例
image.png



▼jsのコンパイルもグローバル指定した場合の例

webpack.mix.js
const mix = require('laravel-mix');
const glob = require('glob');

glob.sync('resources/sass/*.scss').map(function (file) {
  mix.sass(file, 'public/css').options({
    processCssUrls: false,
  });
});

glob.sync('resources/js/*.js').map(function (file) {
  mix.js(file, 'public/js');
});


参考リンク

Laravel公式 Laravel Mix アセットのコンパイル

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LaravelでAuthモデルを呼び出す時って、なんでuse App/Authじゃないの?

Q. LaravelのAuthってなんでApp/Authじゃないの?

Laravelでモデルを呼び出すときuse App/User;とかuse App/〇〇なのに、なんでAuthだけuse Auth;で使えるの?
image.png

A. Authに関する色々な機能はLaravelが作ってるからじゃない?

use Auth;で使える直接の理由は、(プロジェクト名)/routes/web.appで、こう(↓)書かれているから。
image.png

認証機能を有効化した段階、ターミナルで$ php artisan ui vue --authを実行した際に記入される。

『なんでそれができるか』という問いに対する個人的な認識、仮定としては、
Laravelで他のモデルはエンジニアが作るけど、AuthLaravel側が作成するからuse Auth;で使えるようになっている

…としか言いようがなくない?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPのopenssl_encrypt関数で暗号化したものをopensslコマンドで複合化

PHPのopenssl_encryptとopenssl

phpのopenssl_encrypt()で暗号化した文字列をopensslコマンドで複合化しないといけない案件があったのでメモ

エンコード条件

ivを指定してエンコードするのが定石だが、今回はivの指定がなかった。

$enc_key = "abcedfg";
$enc_method = "aes-256-cbc";
$text = "some encode text";

openssl_encrypt($text, $enc_method, $enc_key);

opensslで復号

openssl_encrypt()はIVの指定をしていない場合、key文字列と同じものが指定されるもよう

ポイント
- key文字列を16進数にしたものを-Kオプションに指定する
- ivは-Kオプションに指定した文字の先頭数文字が対応するみたい(文字数はmethod依存?)

/**
 * 文字列を16進数に変換
 * @param $x
 * @return string
 */
function strtohex($x)
{
    $s='';
    foreach (str_split($x) as $c) $s.=sprintf("%02X",ord($c));
    return($s);
}


$key = strtohex($enc_key);
$iv = substr($key, 0, 32);  //$keyの先頭32文字で複合化できた

$cmd = sprintf('echo -n "%s" | openssl enc -d -%s -base64 -A -K %s -iv %s',
  $custom_data, $key, $iv, $iv);

exec($cmd, $out);
echo $out;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】画面に画像を表示する方法。assetsの使い方とurlヘルパ関数との違いについて。

Laravelでブラウザに画像を表示する方法。

1. publicディレクトリに画像をおく

ブラウザが直接読み取るデータなのでpublicディレクトリに設置する。

imgディレクトリを作成しその中に設置。
image.png

2. assetヘルパーで呼び出す

imgタグのsrc属性で、assetsヘルパー関数を使って指定の画像を呼び出す。

<img src="{{ asset('img/cat3.png') }}" alt="">

以上で完了。

image.png


assetヘルパー関数とは?

publicディレクトリ配下の素材へのURLを生成する。

assets('ファイルパス')

ディレクトリの中にある場合は、ディレクトリ名.でつなぐ。

image.png

ビューで呼び出す

ビュー(拡張子 .blade.php)の中で呼び出す場合は、{{ }}をつける。

.blade.php
{{ asset('img/cat3.png') }}
<br>
{{ asset('robots.txt') }}

▼ブラウザの表示

image.png

自分のサイトのpublicフォルダのパスが表示される。

あとは、aタグやimgタグのsrcで指定すれば、各アセットにアクセスできる。

公式ページには以下のように説明されている。(違いはよくわからない)


urlヘルパとassetヘルパの違い

URLを表示するヘルパには、url()という関数もある。

asset()
asset関数は、現在のリクエストのスキーマ(HTTPかHTTPS)を使い、アセットへのURLを生成

url()
url関数は指定したパスへの完全なURLを生成。

結論からいうと、urlassetもほぼ同じ。ただし、urlは引数でパスを渡せるので動的にURLを生成しやすい。


urlヘルパとassetヘルパは同じ使い方ができる

.blade.php
asset: {{ asset('img/cat3.png') }} <br>
<img src="{{ asset('img/cat3.png') }}" alt="">

<hr>

url: {{ url('img/cat3.png') }} <br>
<img src="{{ url('img/cat3.png') }}" alt="">
image.png

全く同じURLが表示される。


urlに特化した使い方

url('prefixのパス', ['後ろに続くパス'])

例1
{{ url('img', ['cat3.png']) }}

image.png


例2
{{ url('column', ['technology', 2020, 1, 10, 'monday']) }}

image.png

動的にURLを指定する際に何かと便利。


参考

Laravel公式 ヘルパ一覧

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】publicとresourcesディレクトリのassets(img, css, js)の違いについて

Laravelのimageファイルやjs, cssファイルの置き場所を探したときに、publicとresourcesディレクトリに混在していることがある。

このpublicとresourcesディレクトリの違いについて。

▼イメージ
image.png

publicとresourcesディレクトリの違い

公開範囲が異なる。

・publicディレクトリ
名前(public)の通り、中身が公開されており、ブラウザが直でアクセスできるデータ。

・resourcesディレクトリ
公開はされておらず、コンパイル前のデータが置かれている。

viewsディレクトリのビュー(.blade.php)もコンパイル前はPHPを含んでいるが、コンパイル後の公開するファイルはHTMLのみとなる。


publicとresourcesディレクトリの使い分け

publicファイルにはブラウザが直でアクセスしてもいいデータを置く。

resoucesの使い方は主に2つ。

(1)サブの画像などを置いておく
公開されないので何を置くかは自分次第。

(2)コンパイルが必要なファイルをおく
.blade.phpやscssなどコンパイル前の元ファイルを置いておく。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【小ネタ】JavaScriptでPHPのlist()っぽいことをやってみる。

はじめに

ドット連結の文字列を分割してそれぞれを変数にできないかなーって考えたときに、もしかしたらJSでもPHPのlist()みたいなことできるんじゃね?って思ったんですよ。

PHPのlist()とは

右辺が配列になるとき、左辺側に列挙した変数に値を入れれるというやつです。
https://www.php.net/manual/ja/function.list.php

list($jeffy, $tockey, $fagimaru) = ['犬', '猿', '雉'];

echo $jeffy; // 犬
echo $tockey; // 猿
echo $fagimaru; // 雉

実はPHP7.1以降は以下の書き方でもいけるんですよね。全然気づかなかった……

[$jeffy, $tockey, $fagimaru] = ['犬', '猿', '雉'];

echo $jeffy; // 犬
echo $tockey; // 猿
echo $fagimaru; // 雉

JSではどうするの?

実はPHPの省略構文と同じです。

const [jeffy, tockey, fagimaru] = ['', '', ''];

console.log(jeffy); // 犬
console.log(tockey); // 猿
console.log(fagimaru); // 雉

「分割代入」っていうんですね。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelで画像をアップロードし、パスをDBに保存する方法

はじめに

Laravelで画像をアップロードし、DBに保存する方法について解説していきます。

まず、今回は画像はプロジェクト内のディレクトリに保存をし、画像のパスをデータベース(以下DB)に保存していきます。
データベースに画像を保存することもできますが、その場合はサイズが大きくなってしまい処理に時間がかかってしまいます。
そのため、画像のパスのみをDBに保存するのが主流のようです。

また、今回はLaravelのプロジェクトは作成し、DBへ接続済であることを前提に進めていくのでご了承ください。

-各バージョン
-laravel 6.x
-PHP 7.4.9
-mySQL 5.7.30

モデルとテーブルを作成する

今回は読書の記録をするアプリを推定して作っていきます。データはシンプルに画像、本の題名、著者名にしたいと思います。

早速、モデルとテーブルをコマンドで作成します。

php artisan make:model Book -m

上記のコマンドを実行すると、Bookモデルとbooksテーブルが作成されます。

続いて、booksテーブルにDBに保存する項目を入力していきます。

books_table_php
public function up()
    {
        Schema::create('books', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title', 100);
            $table->string('author', 100);
            $table->string('image');
            $table->timestamps();
        });
    }

そのままマイグレーションします。

php artisan migrate

問題なくマイグレーションできれば、DBにbooksというテーブルが作成されているはずです。

ビューを作成する

続いて、入力フォームを作っていきます。

upload.blade.php
<form method="post" action="{{ route('upload_image') }}" enctype="multipart/form-data">
   @csrf
   <input type="file" name="image">
   <label for="title">題名</label>     
   <input id="title" type="text" name="title">
   <label for="author">作者</label>     
   <input id="author" type="text" name="author">
   <input type="submit" value="登録">
</form>

まず、画像ファイルをアップデートするには必ずformenctype="multipart/form-dataが必要になります。
また、@csrfはCSRFトークンというもので、外部からの悪意のある攻撃から守るための記述であり、Laravelのフォームには記述が必須となっています。

input内を見ていきます。
画像をアップロードする場合はtype属性をfileに指定します。そしてname属性には先ほどbooks_table_phpで指定したカラム名を指定します。

コントローラーを作成する

まずはコマンドでコントローラーを作成します。

php artisan make:controller BookController

BookControllerが作成されたら、利用するモデル名と、使用するヘルパ関数名を冒頭に記述します。もちろん、あとからその都度記述することも可能です。

BookController.php
use App\Book;
use Illuminate\Support\Str;

そして、画像を保存するための処理を書いていきます。

php
public function store(Stock $request)
  {
      $book = new Book();

      $book->title = $request->input('title');
      $book->author = $request->input('author');

       // 保存されているデータを$formに格納する
       $form = $request->all();
       // もし$formにimageデータがあったら
       if (isset($form['image'])) {
         // $fileにイメージデータを格納する
         $file = $request->file('image');
         // getClientOrientalExtension()でファイルの拡張子を取得する
         $extension = $file->getClientOriginalExtension();
         $file_token = Str::random(32);
         $filename = $file_token . '.' . $extension;
         // 表示を行うときに画像名が必要になるため、ファイル名を再設定
         $form['image'] = $filename;
         $file->move('uploads/books', $filename);
        }
        $book->save();

        return redirect('home');
  }

コードにコメントを書いていないところを解説していきます。

まず、getClientOriginalExtension()でファイルの拡張子を取得した後に、Str::random()でランダムな文字列を取得します。Str::random()は( )内に指定された文字数分、ランダムな文字列を作成することができる関数です。今回は32文字を指定しました。
こうして$filenameには画像のパスが「ランダムな32文字 . 拡張子」の状態で保存されていることになります。

続いてこちらを、move()で任意のファイルに保存するように設定します。move('指定したファイル', 保存するファイル名)の順番で記述をすると、Publicフォルダ内に指定したファイルが自動生成され、アップロードした画像が保存されるようになります。

最後に save()メソッドでデータを保存し、今回はredirect()でhomeに戻るように指定しています。

ルーティングを設定する

upload.blade.php内でformactionroute('upload_image')と指定したので、今回はupload_imagename()で指定し、アクセスをしたら、BookControllerのStoreアクションにつながるように記述します。

web.php
Route::post('/upload', 'BookController@store')->name('upload_image');

これで完成です!

さいごに

今回はLaravelで画像をアップロードし、DBに保存する方法について解説しました。
次回以降、保存したデータを表示する方法や編集方法に関しても解説していけたらと思います!

参考

https://youtu.be/il9gsKH9V-8

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】変数の前の(int)や(string)の意味。変数の型を簡単に変換する方法。

Laravelで変数の前に(int)(string)などが使われていることがあるこの意味について。

(型)$変数名の意味

(型)$変数名で変数の型を変換することができる。
これを型キャストと呼ぶ

つまり、(int)は後に続く変数の方を整数にする処理となる。

型キャストの例
$x = "12000"

$y = (int) $x
echo gettype($y) //integer

$z = ( array  ) $x;
var_export($z);  //array (0 => '2000')

カッコ内や型キャストと変数の間にスペースがあっても機能する。



型キャストでbooleanに変換する場合、値が存在すればtrueに変換される。

$x = "12000"
$z = (boolean)$x;
var_export($z);  //true

使用可能な型キャスト一覧

型キャスト 処理
(int) 整数へのキャスト。(integer)と同じ。
(bool) 論理値へのキャスト。(boolean)と同じ。
(float) float へのキャスト。(double), (real)と同じ
(string) 文字列へのキャスト
(array)  配列へのキャスト
(object) オブジェクトへのキャスト
(unset) NULL へのキャスト

https://www.php.net/manual/ja/language.types.type-juggling.php

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】IoTデバイスからPOST送信されたときに送信元IPアドレスを取得する【ESP32】

はじめに

IoTデバイスをIPアドレスを使って識別しようとしている方,デバイスのIPアドレスをサーバ側で取得したい方向けになります.

環境

  • IoTデバイス(ESP32)
  • ファームウェア(MicroPython1.3)
  • サーバ(Ubuntu18.04)
  • Webサーバ(Apache2)
  • PHP(PHP7.4)

※Apache2を起動して/var/www/html/にPHPプログラム(今回はreceive.php)を置いておくことが前提です.

ソースコード(ESP32)

今回はESP32で適当なJSONデータのPOST送信をし,サーバで送信元のIPアドレスを取得してレスポンスとしてそのIPアドレスを返すようなプログラムにしました.

post.py
import urequests
import ujson

#送信先のURLの指定
#"XXX.XXX.XXX.XXX"にURLを入れる
url = 'http://XXX.XXX.XXX.XXX/receive.php'

#データをDICT型で宣言
obj = {"value" : 123, "text" : "abc"}

#jsonデータで送信するという事を明示的に宣言
header = {'Content-Type' : 'application/json'}

#オブジェクトをJSONに変換し,HTTPリクエストをPOSTとして送信
res = urequests.post(
    url,
    data = ujson.dumps(obj).encode("utf-8"),
    headers = header
)

#サーバ側からのレスポンスを受け取って表示(jsonのデコードも一緒にしている)
print (res.json())

#終了
res.close()

ソースコード(サーバ)

送信元のIPアドレスは$_SERVER[REMOTE_ADDR]に入っているのでそれを変数に入れるなりする.

receive.php
<?php
//送られてきたPOSTデータを受け取って,JSONデータをデコードして$inに入れる.
$json_string = file_get_contents('php://input');
$in = json_decode(stripslashes($json_string),true);

//送られてきたデータを取り出す
$value = $in["value"]; // = 123
$text = $in["text"];   // = abc

//$_SERVER変数を使って送信元のIPアドレスを取得する
//レスポンスを取得したIPアドレスとし,それをJSONとして再度エンコード
//そして送信元(ESP32)へ返す.
$ipAddress = $_SERVER['REMOTE_ADDR'];
//AWS ELBを使用している場合はELBのIPアドレスを取得してしまうので
//以下のようにして元のIPアドレスを取得する
if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
        $ipAddress = array_pop(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
}
//IPアドレスをエンコードして返す
echo json_encode($ipAddress);
?>

実行結果

micropythonのWEB REPLで実行したところ,IPアドレスが返ってきました.

>>> execfile("post.py")
>>> YYY.YYY.YYY.YYY // <- ESP32のIPアドレス

参考

この記事は以下の記事を参考に書いています

[1]
ESP32からMicropythonでHTTPリクエスト(POST)でデータを送信し,PHP(サーバ)で受け取る

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】アンダースコア2つの意味。__()の記述は何をしているのか?

Laravelの__( )の処理内容について。

▼こういうの

例1
@if(__('career.'. $career_slug .'.is_recruiting') === "false")
  //処理
@endif
例2
@include('partials.jumbotron', ['title' => __('page.recruit.career.'. $career_slug .'.title')])

__()の意味

  • __ヘルパ関数と呼ぶ。
  • Lang::getの省略形。

現在設定中の言語ファイルから、指定したデータを呼び出すときに使用する。

現在設定中の言語

config > app.php の中の localeを参照。

image.png

ja(日本語)の場合
 'locale' => 'ja',

言語ファイルの場所

resources > lang配下。

image.png

enはデフォルトでプロジェクトを作成した状態。
jaが後から追加したもの。


__()の使い方

例えば、言語設定が'locale' => 'ja'のときに使うと、jaディレクトリの指定したファイルのデータを取得する。

__('ファイル名')
ファイルの中のデータをごっそり取得

__('ファイル名.プロパティ名')
指定したプロパティのデータを取得


実例

@php
  $career_slug = 'editor' 
@endphp

@if(__('career.'. $career_slug .'.is_recruiting') === "false")
  //処理
@endif

上記処理を確認すると、

__('career.'. $career_slug .'.is_recruiting')`

carrer.phpの、editorプロパティ($career_slug)の、is_recruitingプロパティの値を取得している。

image.png

carrer.php
<?php

return [
    'editor' => [
        'is_recruiting' => 'false',
        'position' => "編集",
        'job_description' => "ライティング業務です"
    ],
];

つまり、取得したデータはfalseとなる。


@if(__('career.'. $career_slug .'.is_recruiting') === "false")

@ifの条件式がtrueになるので処理が実行される。


参考

Laravel公式 ヘルパ関数一覧

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】コンポーネントとスロットの使い方を実例で理解する(@component & @slot)

Laravelで使われるコンポーネント(@component)とスロット(@slot)の使い方について。

Laravel公式のコンポーネントとスロットを参照したがコードにslotが複数あったりで機能がわかりにくいので、要素を分解し確認してみた。


目次

  1. ファイルの準備
  2. コンポーネントの中身をそのまま表示
  3. 変数slotでデータを渡す
  4. 指定したslot名でデータを渡す


ファイルの準備

用意するファイルは2つ。

(1)ビュー
viewsフォルダ直下にcomp-slot.blade.phpを作成。

ディレクトリ
app > resources > views > comp-slot.blade.php



(2)コンポーネント
componentsフォルダの中にtest.blade.phpを作成。

ディレクトリ
app > resources > views > components > test.blade.php

ルーティングの設定

app > routes > web.php にルーティングを追記する。

web.php
Route::get('test', function () {
    return view('comp-slot');
});

パスがtestのURIにアクセスがあったら、ビューファイルcomp-slot.blade.phpを開く。


コンポーネントの使い方

コンポーネントの中身を表示する方法は大きく3つ。

1. コンポーネントの中身をそのまま表示
2. 変数slotでデータを渡す
3. 指定したslot名でデータを渡す

2と3でslotが登場するのがわかりにくい、、それぞれ用途が異なる。


1. コンポーネントの中身をそのまま表示

コンポーネントをそのまま呼び出して表示する。(データの受け渡しをしない)

▼コンポーネント

test.blade.php
<div>
    <p>test.blade.phpです</p>
</div>

▼メインビュー

comp-slot.blade.php
@component('components.test')
@endcomponent

@component('コンポーネントファイル名')

  • ファイル名はviewsからの絶対パスを記載。
  • ディレクトリの中にある場合はディレクトリ名をドットで繋ぐ。


画面表示

comp-slot.blade.phpを開くと、コンポーネントの内容が表示された。

image.png


2. 変数slotでデータを渡す。

次に、元のビューファイルの@componentの中に記載したデータを渡す方法について。

▼メインビュー

comp-slot.blade.php
@component('components.test')
  <p>コンポーネントの中身</p>
@endcomponent

@componentの中にある要素をコンポーネントに{{$slot}}を記載することで好きな場所で呼び出すことができる。

▼コンポーネント

test.blade.php
<div>
    <p>test.blade.phpです</p>
    {{$slot}}
</div>
image.png



▼複数呼び出す

test.blade.php
<div>
    {{$slot}}

    <p>test.blade.phpです</p>

    {{$slot}}
</div>
image.png



{{$slot}}を呼び出さない
{{$slot}}を記述しない場合は、@component内の記載は無視される。

▼コンポーネント

test.blade.php
<div>
    <p>test.blade.phpです</p>
</div>
image.png

注意点

@componentの中身が@slotなどで分断して記述してある場合でも、@slotを除いた、ひとまとまりの要素として出力される。

▼メインビュー

comp-slot.blade.php
@component('components.test')
  コンポーネントの中身

  @slot('xxx')
    slotディレクティブのxxx
  @endslot

  コンポーネントの中身
@endcomponent

▼コンポーネント

test.blade.php
<div>
    {{$slot}}
    <p>test.blade.phpです</p>
</div>
image.png


3. 指定したslot名でデータを渡す

@component内に複数のデータのまとまりを作成し、コンポーネントに渡すには、slot('スロット名')を使う。

呼びだしは{{$スロット名}}とする。

▼メインビュー

comp-slot.blade.php
@component('components.test')
  @slot('xxx')
    slotディレクティブの中身
  @endslot
@endcomponent

▼コンポーネント

test.blade.php
<div>
    {{$xxx}}
    <p>test.blade.phpです</p>
</div>
image.png

@slotを複数設置

ひとまとまりのデータを複数作成することができる。

▼メインビュー

comp-slot.blade.php
@component('components.test')
  <p>コンポーネントの中身</p>

  @slot('xxx')
    slotディレクティブの中身
  @endslot
@endcomponent

▼コンポーネント

test.blade.php
@component('components.test')
  @slot('xxx')
    slotディレクティブのxxx
  @endslot

  @slot('yyy')
    slotディレクティブのyyy
  @endslot
@endcomponent
image.png


まとめ

コンポーネントの中身を表示する方法を一つづつ確認すればだいぶわかりやすい。

1. コンポーネントの中身をそのまま表示
2. 変数slotでデータを渡す
3. 指定したslot名でデータを渡す

最後に、3つを複合すると以下のようなコードになる。

▼メインビュー

comp-slot.blade.php
@component('components.test')
  <p>コンポーネントの中身</p>

  @slot('xxx')
    slotディレクティブのxxx
  @endslot

  @slot('yyy')
    slotディレクティブのyyy
  @endslot

  <hr>
  <p>コンポーネントの中身</p>
@endcomponent

▼コンポーネント

test.blade.php
<div>
    {{$yyy}}

    {{$slot}}
    <p>test.blade.phpです</p>

    {{$xxx}}

    {{$slot}}
</div>
image.png
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】プロジェクトの作成からブラウザ経由のDB操作までを実際にやってみる(アプリ作成の手順詳細)

Laravel学習のため、プロジェクト作成しブラウザからのDB操作(新規追加、編集、削除)を自分でやってみる。

目次

  1. composerのインストール
  2. laravelのインストール
  3. laravelサーバーの起動
  4. DBにsqliteを設定
  5. モデルとマイグレーションの作成
  6. マイグレーションでDBのテーブルにカラムを追加
  7. コントローラの作成
  8. ルーティングの設定
  9. seederを使ってテストデータをDBに設定
  10. 一覧画面の作成(ブラウザにDBの全データを表示)
  11. 詳細ページの作成
  12. 編集機能の作成
  13. 削除機能の作成


1. composerのインストール

composerのインストール方法を参照。


2. laravelのインストール

$ composer create-project laravel/laravel [プロジェクト名] --prefer-dist

指定したプロジェクト名でフォルダが作成される。

--prefer-distオプション
高速ダウンロード用。

このオプションをつけると圧縮されていないファイルを優先してダウンロードする。また、すべてのVSC(バージョン管理ソフト)を取得しないので軽量となる。


3. laravelサーバーの起動

php artisan serve

$ php artisan serve
Starting Laravel development server: http://127.0.0.1:8000

表示されたURLにアクセス
http://127.0.0.1:8000

image.png

上記画面が表示されればOK。
サーバーの停止はctrl + c


DBにsqliteを設定

使用が簡単かつmacにデフォルトでインストールされているsqliteをDBに使用する。

laravelインストール時のデフォルトのDBはMySQLのため、環境ファイルの設定を一部変更する。

.envファイルの変更

ルートディレクトリ直下にある.envファイルを開き、以下コードを変更する。

.env(変更前)
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=root
DB_PASSWORD=

↓ 以下に変更

.env(変更後)
DB_CONNECTION=sqlite

DB用のファイルを作成する

database/database.sqliteを作成する。

プロジェクトのルートディレクトリで以下を実行。

$ touch database/database.sqlite

image.png

モデルとマイグレーションの作成

DBのテーブルに対応するモデルと、テーブルにカラムを追加したり型指定するマイグレーションファイルを作成する。

(参考)モデルとは?マイグレーションとの違い

$ php artisan make:model [モデル名] -m
  • artisanコマンドのmake:modelでモデルを作成する。
  • -mオプションでマイグレーションファイルも同時生成。(--migrateの省略形)
  • モデル名は冒頭大文字の単数形。単語をつなげる場合はキャメルケースにする(例:MakerCode)



▼モデルの命名規則
DBのテーブル名は複数形とし、Model名はその単数形とする。

・DBのテーブル名: 複数形のスネークケース
・対応するModel名: 冒頭大文字のキャメルケース

<例1>
・DBのテーブル名: articles
・対応するModel名: Article

<例2>
・DBのテーブル名: maker_codes
・対応するModel名: MakerCode



▼(例)Productモデルを作成

$ php artisan make:model Product -m

Model created successfully.
Created Migration: 2021_01_15_022833_create_products_table

2つのファイルが生成される。

・モデル
app > Models > モデル名.php
image.png

・マイグレーション
database > migrations > タイムスタンプcreateテーブル名_table.php
image.png

(補足)モデルとマイグレーションファイルを別々に作る場合

マイグレーションファイルは作成用のartisanコードがあるので、それを使って生成できる。

$ php artisan make:model Product
$ php artisan make:migration create_products_table


マイグレーションでDBのテーブルにカラムを追加する

マイグレーションファイルの編集

作成したいカラムを追記する。デフォルトでidとtimestampsのカラムがある。

up関数の中に追記する。

$table->型('カラム名')

2021_01_15_022833_create_products_table.php
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->id();
            $table->string('product_name')->unique(); //追加
            $table->integer('price'); //追加
            $table->boolean('is_stocked')->nullable(); //追加
            $table->timestamps();
        });
    }

必要に応じて、unique()nullable()などの修飾子をつけることができる。


カラムタイプと修飾子

他にもたくさんのカラムタイプが用意されている。
image.png
続きは以下リンク参照。

Laravel公式 使用できるカラムタイプ一覧

▼インデックス修飾子
image.png

▼カラム修飾子
image.png


マイグレーションの実行

作成したマイグレーションファイルの内容をテーブルに反映する。

php artisan migrate



▼migrationの実行例

$ php artisan migrate

Migration table created successfully.
Migrating: 2021_01_15_022833_create_products_table
Migrated:  2021_01_15_022833_create_products_table (0.90ms)

テーブルの作成に成功。

エラー発生時
Illuminate\Database\QueryException
Database (/laravel/test-pj/database/database.sqlite) does not exist. (SQL: PRAGMA foreign_keys = ON;)

対策:$ touch database/database.sqlite を実行


コントローラの作成

DBにデータを追加・読み込み・編集・削除(CRUD操作)するためにコントローラを作成する。

作成時にオプションで-rをつけると、CRUD操作のためのアクションが記載されたコントローラを作成することができる。

$ php artisan make:controller [コントローラ名] -r
  • -r--resourceの省略形
  • コントローラ名は冒頭大文字で、後ろにControllerをつける(例:ProductController)
  • app > Http > Controllerの中にファイルが生成される

--resourceオプションで作成したコントローラを特別にリソースコントローラと呼ぶ。



▼ProcuctControllerの作成例
create, show, editなどCRUD操作に必要なアクションの外枠を既に記述してくれている。
あとは実際の処理を各アクションの中に記述するだけの状態。

$ php artisan make:controller ProductController -r
Controller created successfully.

image.png

▼ファイルの中身

ProductController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProductController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}


ルーティングの設定

先ほど作成したコントローラの各アクションをルートに登録する。

ルーティングは、app > routes > web.php に記述する。

image.png

リソースコントローラのルート登録は、Routeファサードのresourceメソッドで簡単にできる。

web.php
Route::resource('$URI', 'コントローラ名');
  • $URIは複数形のパスを指定する。



▼実例

web.php
Route::resource('products', 'ProductController');

▼ルートの登録状況を確認

$ php artisan route:list

$ php artisan route:list
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
| Domain | Method    | URI                     | Name             | Action                                         | Middleware |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
|        | GET|HEAD  | api/user                |                  | Closure                                        | api        |
|        | GET|HEAD  | products                | products.index   | App\Http\Controllers\ProductController@index   | web        |
|        | POST      | products                | products.store   | App\Http\Controllers\ProductController@store   | web        |
|        | GET|HEAD  | products/create         | products.create  | App\Http\Controllers\ProductController@create  | web        |
|        | GET|HEAD  | products/{product}      | products.show    | App\Http\Controllers\ProductController@show    | web        |
|        | PUT|PATCH | products/{product}      | products.update  | App\Http\Controllers\ProductController@update  | web        |
|        | DELETE    | products/{product}      | products.destroy | App\Http\Controllers\ProductController@destroy | web        |
|        | GET|HEAD  | products/{product}/edit | products.edit    | App\Http\Controllers\ProductController@edit    | web        |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+

リソースコントローラの各アクションがルート登録されている。

Laravel8.xでエラーが出た場合は、RouteServiceProvider.phpのコメントアウトを解除する

(補足)sqliteにテーブルが作成されているか確認する

sqliteにアクセスするためには、sqlite3コマンドで、database.sqliteを開く。

ルートディレクトリで以下を実行。
$ sqlite3 database/database.sqlite

$ sqlite3 database/database.sqlite
SQLite version 3.28.0 2019-04-15 14:49:49
Enter ".help" for usage hints.

#テーブル一覧を表示
sqlite> .table
failed_jobs      password_resets  users          
migrations       products  

#productsテーブルの構造(schema)を表示
sqlite> .schema products
CREATE TABLE IF NOT EXISTS "products" (
  "id" integer not null primary key autoincrement,
  "product_name" varchar not null,
  "price" integer not null,
  "is_stocked" tinyint(1) not null,
  "created_at" datetime null,
  "updated_at" datetime null
);

productsテーブルがあり、指定したカラムを持っていることがわかる。

▼sqlite3の主なコマンド

コマンド 内容
.tables テーブル一覧を表示
.schema [テーブル名] 指定したテーブルのスキーマ定義を表示
.exit sqliteを終了
.help ヘルプを表示


seederを使ってテストデータをDBに設定する

seeder(シーダ)とは、DBを手軽にテストするために、テストデータをDBに設定する機能。

$ php artisan make:seeder シーダ名
  • シーダ名は、[テーブル名]TableSeeder とするのが一般的
  • 保存先: app > database > seeders

なかなか便利な機能で、deleteやedit機能などでデータをあれこれ変更した後に、seederをDBに送ればまた初期のデータを復活させることができる。



▼実例

$ php artisan make:seeder ProductTableSeeder
Seeder created successfully.

image.png

ProductTableSeeder.php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class ProductTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //
    }
}

run関数を持ったクラスが生成される。

seederの編集

seederファイルのrun関数の中に処理を記述する。
今回はクエリビルダで記述する。冒頭でDBファサードのuse宣言をが必要。

ProductTableSeeder.php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB; //追加

class ProductTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        //以下追加
        DB::table('products')->insert([
            [
                'product_name' => 'iPhone6s',
                'price' => 62000,
                'is_stocked' => false
            ],
            [
                'product_name' => 'iPhone8',
                'price' => 84000, 
                'is_stocked' => true        
            ],
            [
                'product_name' => 'iPhone12',
                'price' => 120000,
                'is_stocked' => true               
            ]           
        ]);
    }
}

今回はクエリビルダで記述しているが、Eroquentでも問題ない。

(参考)Eroquetとクエリビルダとは?


seederをDBに反映する

seederをDBに反映する際は、基本的にDatabaseSeeder.phpを使う。
そのため、作成したクラスをDatabaseSeeder.phpの中で呼び出す。

DatabaseSeeder.php
public function run()
    {
        $this->call(ProductTableSeeder::class);
    }

DatabaseSeeder.phpをメインとして使うとseederファイルを複数に分割している場合も容易にDBに反映できる。

#Composerのオートローダを再生成する
$ composer dump-autoload

#DatabaseSeeder.phpを実行する
$ php artisan db:seed



▼実際の処理例

$ composer dump-autoload
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: facade/ignition
Discovered Package: fideloper/proxy
Discovered Package: fruitcake/laravel-cors
Discovered Package: laravel/sail
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.
Generated optimized autoload files containing 4618 classes

$ php artisan db:seed
Seeding: Database\Seeders\ProductTableSeeder
Seeded:  Database\Seeders\ProductTableSeeder (9.16ms)
Database seeding completed successfully.

以上でseederで作成したデータをDBに反映完了。



▼(補足)別のseederファイルを直接DBに反映する
DatabaseSeeder.phpではなく、別途作成したseederファイルのみ読み込ませたい場合は、--classオプションでseederを指定する。

php artisan db:seed --class=ProductTableSeeder


DBのデータを確認する

・DBのデータを抽出してみる

artisanコマンドのtinkerを使って、Laravelの対話モードに入り、Eloquentのallメソッドで指定したモデルのすべてのデータを取得する。

$ php artisan tinker
>>>[モデルの完全な名前空間]::all();

対話モードはexitで抜ける。

tinkerの元の意味は小さな改善をすること。phpの対話モードでコマンドを一つづつ実施することが由来している?



▼実例

ターミナル
$ php artisan tinker
Psy Shell v0.10.5 (PHP 7.3.11  cli) by Justin Hileman
>>>
>>> App\Models\Product::all();
=> Illuminate\Database\Eloquent\Collection {#4309
     all: [
       App\Models\Product {#4308
         id: "1",
         product_name: "iPhone6s",
         price: "62000",
         is_stocked: "0",
         created_at: null,
         updated_at: null,
       },
       App\Models\Product {#4307
         id: "2",
         product_name: "iPhone8",
         price: "84000",
         is_stocked: "1",
         created_at: null,
         updated_at: null,
       },
       App\Models\Product {#4298
         id: "3",
         product_name: "iPhone12",
         price: "120000",
         is_stocked: "1",
         created_at: null,
         updated_at: null,
       },
     ],
   }
>>>
>>> exit
Exit:  Goodbye

指定したデータが取得できている。


・sqliteで確認する

ルートディレクトリで以下を実行。
$ sqlite3 database/database.sqlite

テーブルの中のデータをすべて表示(SQL)
select * form [テーブル名]

$ sqlite3 database/database.sqlite

sqlite> select * from products;
1|iPhone6s|62000|0||
2|iPhone8|84000|1||
3|iPhone12|120000|1||

sqlite> .exit


一覧画面の作成(ブラウザにDBの全データを表示)

取得した全データを表示する一覧画面を作成する。

コントローラのindexアクションを編集する

以前に作成したコントローラのindexアクションの戻り値にDBのすべてのデータを指定する。

Eloquentを使うため冒頭に使用するモデルのクラスをuse宣言する。

ProductController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Product;  //追記

class ProductController extends Controller
{
    public function index()
    {
        $productsInfo = Product::all(); //追記
        return $productsInfo; //追記
    }

//以下略

(参考)Eroquetとは?

サーバーを起動する

$ php artisan serveを実行する。

$ php artisan serve

Starting Laravel development server: http://127.0.0.1:8000


ブラウザで表示する

URIにindexに対応するルートを入力する。(ここでは /products)

ルートは、$php artisan route:listコマンドで確認できる。

image.png

取得したデータの表示に成功。取得データをそのまま返しているのでデータはJSON形式で表示される。


ビューの作成

取得データを見やすく表示するためにビューを作成する。
ビューは resources > views 配下に、拡張子.blade.php
で保存する。

今回は、productsディレクトリを作成し、外側となるbase.blade.phpとメイン部分となるindex.phpを用意する。

▼ディレクトリ構造
image.png

レイアウトの作成

layoutsディレクトリの中にbase.blade.phpを作成する。

base.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>@yield('title')</title>
</head>
<body>
  <h1>@yield('title')</h1>

  @yield('content')
</body>
</html>

メインビューの作成

index.blade.phpを作成する。

index.blade.php
@extends('.products.layouts.base')

@section('title', '製品一覧')

@section('newLink')
  <a href="/products/create">新規作成</a>
  <hr>
@stop

@section('content')
  @foreach ($products as $product)
    <div>
      <h2>{{$product->product_name}}</h2>
      <p>製品価格{{number_format($product->price)}}</p>
      <p>在庫
        @if ($product->is_stocked) あり 
        @else なし
        @endif
      </p>
      <a href="/products/{{$product->id}}/edit">編集する</a> | 
      <a href="/products/{{$product->id}}">商品詳細</a>
      <hr>
    </div>
  @endforeach
@stop

後々作成する、新規作成、編集、商品詳細ページへのリンクも設置してある。

(参考)section, yield, extendsについて


コントローラでビューを指定

ProductControllerのindexアクションで、作成したビュー(index.blade.php)を開くように処理を変更する。

ProductController.php
<?php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Product;  //追記

class ProductController extends Controller
{
    public function index()
    {
        $productsInfo = Product::all();
        return view('products.index', ['products' => $productsInfo]);   //変更
    }

//以下略
  • viewをviewヘルパーと呼び、指定したビューを開く。その際、第2引数でデータを渡せる。
  • resource > products > index.blade.phpは、products.indexとして指定。
  • 第2引数の書き方: ['変数名' => 渡すデータ]



▼ブラウザの表示
保存して、サーバー起動php artisan serve
し、URIを入力する。

http://127.0.0.1:8000/products

image.png

DBから取得したデータが成形して表示されている。


詳細ページの作成

商品詳細ページを作成する。

コントローラの編集

ProductControllerのshowアクションを編集する。

ProductController.php
    public function show($id)
    {
        //受け取ったidの製品情報を格納
        $product = Product::find($id);
        return view('products.show', ['product' => $product]);
    }

URLのproductsの後ろのデータが$idとして渡される。
findメソッドを使って、指定したidのデータを変数$productに格納する。


ビューの編集(show.blade.php)

resources > products 配下にshow.blade.phpを作成する。

show.blade.php
@extends('.products.layouts.base')

@section('title', '製品詳細')

@section('content')
  <div>
    <h2>{{$product->product_name}}</h2>
    <p>製品価格{{number_format($product->price)}}</p>
    <p>在庫
      @if ($product->is_stocked) あり 
      @else なし
      @endif
    </p>
    <a href="/products/{{$product->id}}/edit">編集する</a> |  
    <a href="/products">製品一覧に戻る</a> |
    @component('components.delete-txt', ['product'=>$product])
    @endcomponent
    <hr>
  </div>
@stop

あとは、http://127.0.0.1:8000/products/1 のように、末尾でidを指定すると製品詳細ページが開く。

image.png

編集と削除リンク先は後ほど作成。



▼(補足)削除機能のボタン
削除機能はcomponentとして読み込んでいる。詳細の機能は最後の削除機能で作成する。

    @component('components.delete-txt', ['product'=>$product])
    @endcomponent


新規追加機能の作成

ルーティングの確認

DBに保存するには、createアクションを実行し、storeアクションを行う。

ルートを確認すると、/products/createでcreateアクションを実行、/productsにPOSTでアクセスするとstoreアクション実行となる。

$ php artisan route:list
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
| Domain | Method    | URI                     | Name             | Action                                         | Middleware |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
|        | POST      | products                | products.store   | App\Http\Controllers\ProductController@store   | web        |
|        | GET|HEAD  | products/create         | products.create  | App\Http\Controllers\ProductController@create  | web        |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+


createビューの作成

新規作成ページとして、create.blade.phpを作成する。

create.blade.php
@extends('.products.layouts.base')

@section('title', '製品の新規追加')

@section('content')
  <form action="/products" method="post">
    @csrf
    <div>
      <label for="product_name">製品名</label>
      <input type="text" name="product_name" required autoforcous>
    </div>
    <div>
      <label for="price">製品価格
      </label>
      <input type="text" name="price" required>
    </div>
    <div>
      <label for="stock">在庫有無</label>
      <select name="stock">
        <option value="1">あり</option>
        <option value="0">なし</option>
      </select>
    </div>
    <div>
    <div>
      <input type="submit" value="送信">
    </div>
  </form>
@stop

@csrf
クロスサイトリクエストフォージェリ対策として必須

(参考)Laravel公式 CSRF保護

@csrfの記述がないと、submit後に419のエラーページに飛ばされる。(419はLaravel独自のエラーページ)

image.png


コントローラの編集

新規追加のためには、createアクションとstoreアクションの2つに処理を追加する。

createアクション

createアクションでは、上記で作成したビューを表示させるのみ。

ProductController.php
    public function create()
    {
        return view('products.create');
    }

storeアクション

storeアクションでは、submitで送られてきたデータを受け取り、DBに保存する処理を記述する。

ProductController.php
    public function store(Request $request)
    {
        $product = new Product;

        $product->product_name = $request->product_name;
        $product->price = $request->price;
        $product->is_stocked = $request->stock;

        $product->save();

        return redirect('products/'.$product->id);
    }

$product = new Product;
Productモデルからインスタンスを作成し、変数に代入。
この変数に各データを保存していく。

$request->[name属性]
submitで送られてきたデータは$requestに保存されている。
name属性を指定してデータを取得する。

$product->save();
すべてのデータを格納したら、saveメソッドでDBに保存する。

return redirect('products/'.$product->id);
新たに作成した製品詳細ページにリダイレクトする。


ブラウザで開く

ブラウザでcreateページを開く。
http://127.0.0.1:8000/products/create

image.png

↓ 送信

image.png

新規保存し、新しい製品詳細ページの表示に成功。


編集機能の作成

ルーティングの確認

既存商品の情報を編集するには、editアクションとupdateアクションを使う。

$ php artisan route:list
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
| Domain | Method    | URI                     | Name             | Action                                         | Middleware |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
|        | PUT|PATCH | products/{product}      | products.update  | App\Http\Controllers\ProductController@update  | web        |
|        | GET|HEAD  | products/{product}/edit | products.edit    | App\Http\Controllers\ProductController@edit    | web        |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+

products/{product}/editにアクセスして、商品の編集を行い、products/{product}にPUT|PATCHでアクセスすればDBの情報を更新できる。


編集ページの作成

編集用のビュー、edit.blade.phpを作成する。
基本的にはcreate.blade.phpと同じ。PUTでアクセスするために擬似メソッドを設置する。

▼create.blade.phpとの違い

  • formタグのactionでパスが変わる。
  • 擬似フォームメソッドの@method('PUT')を設置。
  • inputタグにvalue属性で既存の設定データを表示。
  • 在庫の有無に合わせてselectタグの初期値を設定。
  • submitボタンのvalueを更新に変更。
edit.blade.php
@extends('.products.layouts.base')

@section('title', '製品の編集')

@section('content')
<form action="/products/{{$product->id}}" method="post">
    @csrf
    @method('PUT')
    <div>
      <label for="product_name">製品名</label>
      <input type="text" name="product_name" value="{{$product->product_name}}" required autoforcous>
    </div>
    <div>
      <label for="price">製品価格
      </label>
      <input type="text" name="price" value="{{$product->price}}" required>
    </div>
    <div>
      <label for="stock">在庫有無</label>
      <select name="stock">
        @php 
          $selected = "selected";
          if ($product->is_stocked)
            $selected = ""
        @endphp
        <option value="1">あり</option>
        <option value="0" {{$selected}}>なし</option>
      </select>
    </div>
    <div>
      <input type="submit" value="更新">
    </div>
  </form>
@stop



・擬似フォームメソッド
HTMLフォームはPUT, PATCH, DELETEリクエストを作成できないため(対応していない)、_methodを偽装する必要がある。

<input type="hidden" name="_method" value="リクエストメソッド名">

type="hidden"をつけると画面上に表示していないデータを送信することができる。_methodというキー名で、指定したリクエストメソッドを値として送信している。

▼putを使う方法
送信ボタンの上に以下タグを設置する。

edit.blade.php
<input type="hidden" name="_method" value="put">
<input type="submit" value="更新">

これを、laravelの擬似フォームメソッドを使うととても簡単にかける。

@method('PUT')

・(参考)Laravel公式 擬似フォームメソッド


(補足)PUTとPATCHの違い
PUTはすべてのデータをまるごと変更する場合に使い、PATCHは一部のデータを変更する場合に使うらしい。
ここでは、PUTとPATCHどちらを使っても同じ結果になる。


コントローラの編集

editアクションとupdateアクションを編集する。

editアクション

Productモデルの指定したidのデータを取得してビューに渡す。

ProductController.php
    public function edit($id)
    {
        $product = Product::find($id);
        return view('products.edit', ['product'=>$product]);
    }

updateアクション

記述はstoreアクションとほぼ同じ。
最初にProductモデルの新規インスタンスではなく、指定したidのデータを取得する。

受け取ったデータ$requestを代入し、saveでDBに保存する。

ProductController.php
    public function update(Request $request, $id)
    {
        $product = Product::find($id);

        $product->product_name = $request->product_name;
        $product->price = $request->price;
        $product->is_stocked = $request->stock;

        $product->save();

        return redirect('products/'.$product->id); 
    }


削除機能の作成

ルーティングの確認

$ php artisan route:list
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
| Domain | Method    | URI                     | Name             | Action                                         | Middleware |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+
|        | DELETE    | products/{product}      | products.destroy | App\Http\Controllers\ProductController@destroy | web        |
+--------+-----------+-------------------------+------------------+------------------------------------------------+------------+

products/{product}にDELETEでアクセスすればデータを削除できる。

削除コンポーネントを作成する

削除ボタンは編集と詳細ページに設置する。laravelの機能であるコンポーネント化し簡単に呼び出しを行う。

コンポーネントはボタンとテキストの2種類を用意する。

▼編集
image.png

▼詳細
image.png

ファイルの作成

resources > views > componentsの配下に、ファイルを2つ作成する。

image.png

▼削除ボタンコンポーネント

delete-btn.blade.php
<form action="/products/{{$product->id}}" method="post" id="delete-btn">
      @csrf
      @method('DELETE')
      <input type="submit" name="" value="削除">
</form>

・acrtion属性の値に"/products/{{$product->id}}"を設定。

formはDELETEメソッドをサポートしていないため、ここではpostを指定。

@csrf
クロスサイトリクエストフォージェリ防止機能を追加(必須!)

@method('DELETE')
擬似フォームメソッドでDELETEを指定。これでdeleteメソッドで通信できるようになる。

▼削除テキストコンポーネント

delete-txt.blade.php
<form action='/products/{{$product->id}}' method='POST' id='dlt-txt'>
  @csrf
  @method('DELETE')
  <a onclick='document.getElementById("dlt-txt").submit()'>削除する</a>
</form>

inputタグをテキストに変更するため、JavaScriptのsubmitメソッドを使用。

formタグにid="dlt-btn"を指定し、sbumitの対象をdocument.getElementById(dlt-btn)とする。

以上でコンポーネントが完成。


componentの仕組み

前述のコードで既にcomponentの呼び出し処理は記述してあるが、componentの仕組みについて。

Laravelではblade.phpファイルをコンポーネントとして呼び出すことができる。

extends, yield, sectionの簡易的な機能のようなもの。

コンポーネントの呼び出しはとても簡単で、呼び出したいところに以下のコードを記述する。

  @component('ビューのパス', ['変数名'=>渡したいデータ])
  @endcomponent

ビューのパスは相対ではなく、viewsフォルダからの絶対パスとなる。

image.png

このため、products > edit.blade.php から components >
delete-text.blade.phpを呼び出したい場合は、components.delete-txtとする。

第2引数はデータを渡したいときに使う。読み込むのみでデータを渡す必要がない場合は不要。


ブラウザの表示(削除機能の確認)

image.png

↓ 商品詳細(iPhone8)

image.png

↓ 削除

image.png

削除成功。



バリデーション、CSSの調整はないが、LaravelのCRUD操作の基本はおさえられた。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vagrant(仮想化)でLaravel環境の構築について自分なりにまとめてみた(Windows10)

はじめに

Laravelでの環境構築の際にLaravelの公式ドキュメント様よりVagrant環境(仮想環境)で構築するよう記述されていたので私自身のアウトプットのために記事にしてみました。

目次

  1. 環境構築
  2. 使ってみてわかったこと
  3. 参考文献

環境構築

Vagrantとは、ローカル環境内に仮想環境を比較的簡単に構築することだと認識しています。
詳細はIT用語辞典にて確認をお願いします。
では、環境構築についてはじめようかと思います。
まずは手順1~手順3まで入れてください。
手順1:VirtualBoxを入れる。
手順2:Vagrantを入れる。
手順3:Gitを入れる。

下記コマンドは、homesteadに用いる仮想環境の下地を作成する

vagrantコマンド
 vagrant box add laravel/homestead

gitコマンドより、Homesteadディレクトリを作成してhomesteadを入れる。

Gitコマンド
 git clone https://github.com/laravel/homestead.git Homestead

cd /Homesteadのディレクトリに入る

.bash
cd /Homestead 

初期設定ファイルを作成(初めての場合は絶対にする)

.bash
./init.sh
#下記コマンドが表示されたらOK
>Homestead initialized!

homesteadに移動してyamlファイルを入れる。

.bash
cd ~/.homestead/
vi Homestead.yaml

※viは、linux上でテキストを編集するコマンドです。(類似でvimがある)
簡単なコマンド
文字の挿入:「i」
挿入から抜ける:「Esc」ボタン
保存:「:wq!」

yamlファイルの編集

Homestead.yaml
ip: "192.168.10.10" #接続先となるIPアドレス
memory: 2048 #割り当てるメモリ(MB)※2ギガこのこと
cpus: 1 #同CPUのコア数
provider: virtualbox #VMのホスト

authorize: ~/.ssh/id_rsa.pub #SSH公開鍵の場所
#上記の設定でhttp→httpsでも接続できるように設定しておいた方がよい
#なぜなら、ajaxでの送信ができない為、今は無視してもよい

keys:
    - ~/.ssh/id_rsa #秘密鍵の場所

folders:
    - map: C:\homestead\Laravel #ローカルのディレクトリ
      to: /home/vagrant/Code #VM上のディレクトリ

sites:
    - map: homestead #ホスト名
      to: /home/vagrant/Code/Laravel/public #web上に公開するディレクトリ(Apacheのhtdocsみたいなもん)

databases:
    - homestead

公開鍵と秘密鍵を生成する

.bash
cd ~/.homestead/
mkdir ~/.ssh && cd $_
#鍵作成
ssh-keygen -b 4096
#パスフレーズを入れる・入れないは自由。鍵ファイル名はHomestead.yamlのそれと合わせるようにしてください。
Generating public/private rsa key pair.
Enter file in which to save the key (xxxxx): ~/
Enter passphrase (empty for no passphrase):
#2回パスワード聞かれるので適当にパスワードを入力してください
※忘れないように!!
Enter same passphrase again:

上記より生成されているか確認する
下記は確認コマンドより(id_rsa(秘密鍵),id_rsa.pub(公開鍵))

.bash
cd ~/.ssh

hostsファイルの書き換え(C:\Windows\System32\drivers\etc\hosts)
権限により編集できないのでテキストファイルで開きなおしてください。
hostsの書き換え方

hosts
#下記を追加する一番したに追加する
192.168.10.10 homestead

※補足として仮に複数のアプリと連動させたい場合は、192.168.10.10 プロジェクト名 プロジェクト名1
のように引数みたいに記述すればよい。

vagrantの実行

hosts
#下記を追加する
vagrant up

※vagrant up (vagrantの起動),vagrant up --provision(起動時に起動),vagrant reload(再起動)
vagrant halt(仮想のシャッドダウン)今はこれぐらいのコマンドでよい。

このようなエラーがでた場合は、gitbashの文字コードをUTF-8からshift-jisでできるようになる。
まあ「encode!」っていってのるので修正しましょー。
※Git Bashを右クリックしてoption→text→文字コード(shift-jis)と変更する。

hosts
#下記を追加する
C:/HashiCorp/Vagrant/embedded/gems/2.2.10/gems/childprocess-4.0.0/lib/childprocess/windows/process_builder.rb:44:in `encode!': "\xE8" to UTF-8 in conversion from ASCII-8BIT to UTF-8 to UTF-16LE (Encoding::UndefinedConversionError)
        from C:/HashiCorp/Vagrant/embedded/gems/2.2.10/gems/childprocess-4.0.0/lib/childprocess/windows/process_builder.rb:44:in `to_wide_string'
        from C:/HashiCorp/Vagrant/embedded/gems/2.2.10/gems/childprocess-4.0.0/lib/childprocess/windows/process_builder.rb:67:in `create_environment_pointer'
        from C:/HashiCorp/Vagrant/embedded/gems/2.2.10/gems/childprocess-4.0.0/lib/childprocess/windows/process_builder.rb:28:in `start'
        from C:/HashiCorp/Vagrant/embedded/gems/2.2.10/gems/childprocess-4.0.0/lib/childprocess/windows/process.rb:70:in `launch_process'

これで下記URLでLaravelの画面が表示されたら完了です。
http://homestead/

使ってみてわかったこと

取り敢えず、linuxコマンドに強くなるのかな~と思います。後は、簡単にアプリを配置したり削除できたりする事が可能なので便利だと思います。仮想化の勉強になるしURLも汚れないし(localhost8080はちょっと恥ずかしいかな?)以上になります。

ほとんどこの方を参考にしました
有難うございます。

追記:できれば間違っている点やおかしな点があれば教えて頂けると幸いです。

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む