- 投稿日:2019-05-30T23:56:26+09:00
Laravel-Eloquent(Mysql)で、select結果に固定値カラムを追加する方法(使用例)
mysql
select '1' as sample;Laravel
$list = SampleModel::select('id', DB::raw("'1' as sample"))->get();真偽値なんかを扱いたいときは
$list =SampleModel::select('id', DB::raw("1 = status as sample"))->get();trueは1が入り、falseの場合は0が入る。
どういったときに便利か
Sampleテーブルのカラムにstatusカラムが存在し、そのstatusの中身が1,2,3の場合だった場合、1の時はこのボタンを表示したいんだけどなぁと思ったときに、カラムを足さない場合は、
blade@foreach($list as $item) @if((int)$item->status === 1)といったような文を書くことがあるとします。この形は、Viewのほうには、なるべくロジックを加えたくないし、1は何を示しているのかわかりません。そのために、SampleModelに定数を定義します。
SampleModel.phpconst STATUS_HAPPY = 1; const STATUS_SAD = 2;bladeを修正します。
blade@if((int)$item->status === \App\Models\SampleModel::STATUS_HAPPY)これで、statusがHappyの時は、なにかするんだなとわかりやすくなりましたが、if分の中が長くなってしまいました。そのため、データにstatusがhappyがどうかのフラグを持たせる処理を作ってみます。
$list = SampleModel::select('id', 'status')->map(function ($row){ $row->is_happy = ((int)$row->status === SampleModel::STATUS_HAPPY); });blade@if($item->is_happy)先ほどより、bladeのほうの処理は、短くなりよくなりました。ただ、phpの処理のほうをis_happyだけのために、mapを回したく無く感じますので、selectでとっちゃいます。
$list = SampleModel::select('id', 'status', DB::raw(SampleModel::STATUS_HAPPY. ' = status as is_happy'))->get();これで、statusカラムの中身とSampleModel::STATUS_HAPPYが一致した場合はis_happyは1で、一致しない場合は0が入りますので、
bladeでそのまま使えます。blade@if($item->is_happy)フラグ用にmapをまわすメソッドを別で作ったりするより、いい気がする。次からつかお
- 投稿日:2019-05-30T23:32:00+09:00
Laravel 2つの異なるテーブルを合わせて、ページネーションをかける
Apple・Lemonテーブル
public function test(Request $request) { $subQuery = Apple::from('apples as A') ->select('A.id', 'A.name'); $list = Lemon::from('lemons as L') ->select('L.id', 'L.name') ->UnionAll($subQuery) ->orderBy('name', 'asc') ->paginate(10); return view('test', [ 'paginate' => $list, ] ); }unionは、重複を削除します。UnionAllは重複を削除しません。
union allコストについて参考記事異なるDBを見たい場合
public function test(Request $request) { $subQuery = Apple::from('sample1.apples as A') ->select('A.id', 'A.name'); $list = Lemon::from('sample2.lemons as L') ->select('L.id', 'L.name') ->UnionAll($subQuery) ->orderBy('name', 'asc') ->paginate(10); return view('test', [ 'paginate' => $list, ] ); }テーブルの前にDB名.で指定すると別々のDBを見に行ってくれます。
- 投稿日:2019-05-30T19:34:25+09:00
PHPスクラッチでECサイト構築
カート機能 備忘録
カート機能利用の流れ
商品一覧画面 → 商品詳細画面 → 商品の個数を入力し、カートに商品を入れる
カートに必要な機能
- クライアントが選んだ商品IDの保持
- 商品数量の保持
- 複数の商品をカートに格納することができること
PHPで重要となる構文
スーパーグローバル変数SESSIONの利用
→ クライアントが選んだ商品IDと商品数量を保持するために多次元配列をSESSIONに保存する解説の流れ
1.商品IDの受け渡し
2.多次元配列をSESSIONに格納
3.var_dumpを利用した出力の確認
4.カートに商品を複数保持する1.商品一覧画面(product_list.php)→商品詳細画面(product_detail.php)における商品IDの受け渡し
product_list.php<form action = "product_detail.php" method = "post"> <input type = "submit" value = "詳細" /> <input type = "hidden" name = "id" value = "<?php echo $val['id'];?>"> </form>product_detail.php$id = $_POST['id'];2.多次元配列をSESSIONに格納
下記のように記述することで、商品IDと商品個数を多次元配列でSESSIONに格納することができる
product_detail.php$_SESSION['cart'][$id]=array( 'id'=>$_POST['id'], 'number'=>$_POST['num'], //$_POST['num']はクライアントが選んだ商品数量 );3.var_dumpを利用した出力の確認
var_dump($_SESSION['cart']);出力結果
array(1) { [1]=> array(2) { ["id"]=> string(1) "1" ["number"]=> string(1) "5" } }この出力結果はSESSION['cart']に商品IDが1の商品が5個挿入されたことを表している
4.カートに商品を複数保持する
if文でカート内に既に商品が格納されているかどうか判断し、商品が存在すれば商品個数を足し、商品が存在しなければ、SESSIONに商品を格納するというプログラムの内容になっている
product_detail.phpif(isset($_SESSION['cart'][$id])){ $_SESSION['cart'][$id]['number'] +=$_POST['num']; header('Location:product_list.php');exit(); }else{ $_SESSION['cart'][$id]=array( 'id'=>$_POST['id'], 'number'=>$_POST['num'], ); header('Location:product_list.php');exit(); }出力結果
array(3) { [3]=> array(2) { ["id"]=> string(1) "3" ["number"]=> int(6) } [1]=> array(2) { ["id"]=> string(1) "1" ["number"]=> string(1) "3" } [2]=> array(2) { ["id"]=> string(1) "2" ["number"]=> string(1) "4" } }カートに商品を複数格納することが可能になった。
- 投稿日:2019-05-30T18:04:37+09:00
Selenium で web サーバ上のファイルの中身を取得する
はじめに
Selenium を使用して, web サーバ上のファイルの中身を取得する方法です.
ダウンロードボタンを Selenium に押させて, ファイルを実際にダウンロードした後に中身を取得することも可能ですが,
その場合, ダウンロードしたファイル名を特定する必要があり, それが困難だったりします.そこで, JavaScript の XMLHttpRequest() を使いファイルの中身1を取得する方法を, ケース毎のサンプルコードで紹介します.
ケース1: href の場合
index.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <a href="https://localhost/files/hoge.csv">download</a> </body> </html>main.php$webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub'); $webDriver->get('https://localhost/index.html'); $url = $webDriver->findElement(WebDriverBy::tagName('a'))->getAttribute('href'); $responses = $webDriver->executeScript(implode('', ['var xhr = new XMLHttpRequest();', 'xhr.open("GET", "' . $url . '", false);', 'xhr.overrideMimeType("text/plain; charset=Shift_JIS");', 'xhr.send();', 'return xhr.responseText;'])); var_dump($responses); $webDriver->quit();ケース2: form method="get" の場合
index.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="https://localhost/files" method="get"> ... <input type="submit" value="download"> </form> </body> </html>main.php$webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub'); $webDriver->get('https://localhost/index.html'); $responses = $webDriver->executeScript(implode('', ['var form = document.querySelector("form");', 'var xhr = new XMLHttpRequest();', 'xhr.open("GET", form.action + "?" + new URLSearchParams(new FormData(form)).toString(), false);', // form.method => get, form.action => 'https://localhost/files/' 'xhr.overrideMimeType("text/plain; charset=Shift_JIS");', 'xhr.send();', 'return xhr.responseText;'])); var_dump($responses); $webDriver->quit();ケース3: form method="post" の場合
index.html<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="https://localhost/files" method="post"> ... <input type="submit" value="download"> </form> </body> </html>main.php$webDriver = RemoteWebDriver::create('http://localhost:4444/wd/hub'); $webDriver->get('https://localhost/index.html'); $responses = $webDriver->executeScript(implode('', ['var form = document.querySelector("form");', 'var xhr = new XMLHttpRequest();', 'xhr.open(form.method, form.action, false);', // form.method => post, form.action => 'https://localhost/files' 'xhr.overrideMimeType("text/plain; charset=Shift_JIS");', 'xhr.send(new FormData(form));', 'return xhr.responseText;'])); var_dump($responses); $webDriver->quit();注意事項
スクレイピングを禁止しているサイトもありますのでご利用の際はお気をつけくださいませ.
今回, web サーバ上のファイル = CSV ファイル を想定 ↩
- 投稿日:2019-05-30T16:48:52+09:00
WordPressを使ったサイト制作標準フロー
WordPressを使ったサイト制作案件が多く手がけるようになって、この1年だけで10サイト以上WordPress案件に携わってきました。
色々と試行錯誤しながらやってきたなかで、ある程度WordPressをつかったサイト制作のフローが標準化してきたのでまとめていきたいと思います。前提事項
- Web制作会社などでいちからサイトを制作することを想定
(汎用テーマなどを使って簡易に構築するとかではなく、ガッツリとそのサイト専用のテーマを作成する)- それぞれのツールのインストール方法などは記載しない
(Qiita内で丁寧に手順を記載している記事があるので検索してみてください)Web制作にWordPressを導入した際の課題
- 環境構築が手間。
- 新規テーマ作成時の初期テンプレートの準備が大変。
- サイトの引っ越しが生じる都度、DBの書き換えが必要となる。
- 各操作がWeb画面のGUIベースで作業を自動化やコード化しにくい
対応策
1. 環境構築が手間。
VCCWで環境構築の手間を解決する
LAMP環境をホストOSに構築したり、VirtualBoxでゲストOSに構築したりしてWordPressをインストールしている時期もありましたが、VCCWの存在を知ってからはWordPress案件はすべてVCCWを使用しています。
VCCWを使えばコマンドひとつでWordPress開発環境をVagrant上に構築可能。
PHP_CodeSnifferやWP-CLI、WordMoveなどの便利なWordPress関連ツールもついてきて非常に便利です。2. 新規テーマ作成時の初期テンプレートの準備が大変。
Iemotoで骨組みとなるテーマファイルを一括生成
WordPressのオリジナルテーマをつくる際は、既存のデフォルトテーマを元にコピーして作成する方法などもありますが、コード内の名前を置換したり不要な記述を削除するが手間です。
Iemotoを使用するといくつかの質問に答えるだけで、WordPressの基本的なテーマファイル構成とSassのコンパイルなどを行なうタスクランナーの設定まで自動でやってくれます。
(後述する、WP-CLIでもテーマの雛形を作成できますが、タスクランナーがついている分、Iemotoのほうが便利です。)
Use gulp? (y/N)はyでGruntではなく、Gulpのほうが動作が早いのでオススメ。
タスクランナーの実行はゲストOS側でも良いですが、ホストOSから実行したほうが楽だし早いので私はホスト側から実行しています。3. サイトの引っ越しが生じる都度、DBの書き換えが必要となる。
WordMoveでデプロイや他環境との同期を効率化
WordPressはパスをすべて絶対パスで記述するような方針のため、ローカルの内容をテスト環境へアップしたり、テスト環境の内容を本番に反映したりする際にDB書き換えが必要となり非常に手間です。
以前は自分でドメイン部分を変換して適用するようなコマンドラインツールを作成していましたが、やはり自分が困っていることは他の人も困っていて、すでに WordMoveという一般的な解決策がありました。
WordMoveを使えば、簡単にプラグイン、テーマ、DB、メディアなどを指定しそれぞれの環境と同期することが可能です。
よくあるケース
途中で参加したプロジェクトメンバーがステージング環境のデータを開発環境に同期する。
wordmove pull -e staging -t -d -u -pDBやメディア(アップロード画像)はGitなどで管理しないことが多いと思いますが、VCCWの設定ファイルなどをGitで管理している場合、新しくプロジェクトに参加する人はリポジトリをクローンした後はVagarntを立ち上げて、WordMoveで上記のようにステージングのデータを取ってくるだけですぐに作業を開始できます。
本番環境に修正したテーマを適用する。
wordmove push -e production -tテーマファイルの修正をステージングにアップ後に本番環境へ反映するには上記のようにコマンドひとつで簡単に実行できます。
4. 各操作がWeb画面のGUIベースで作業を自動化やコード化しにくい
WP-CLIで作業をショートカット、シェルスクリプト化など
WP-CLIを使うとWordPressに関わる様々な作業がコマンドラインから簡単に行えます。
コマンドラインから行えるということは社内wikiで手順を共有しやすく、シェルスクリプト化も容易です。よく使うコマンド例:
# WordPressのアップデート wp core update # プラグインをインストールして有効化 wp plugin install classic-editor --activate # DBバックアップ wp db export ~/backup.sql # DBをリセットしてからインポート wp db reset && wp db import ~/backup.sqlパーミッションや設定の問題で管理画面からプラグイン追加や更新が出来ない場合でも、SSHでサーバー接続可能な場合はWP-CLIから対応できますし、ログインアカウントが不明な場合もWP-CLIからアカウントを追加することが出来ます。
カテゴリ情報や固定ページなど初期データが大量にある場合もWP-CLIをつかったシェルスクリプトで一括で登録できるようにすると便利です。
まとめ
- WordPressを使ったサイト制作ではまずはVCCWを使う
- テーマ作成はコピーではなく、Iemotoをつかって生成するのが吉
- 各環境間のデータ連携はWordMoveを使う
- 必要な作業はコマンドライン(WP-CLI)から行えないか検討する
- 投稿日:2019-05-30T16:30:06+09:00
【PHP】PHPからApacheのバージョンを取得する
PHP から Apache のバージョンを取得する方法についての記事です。
コード
function apacheVersion($pShell = null) { $shell = (isset($pShell)) ? $pShell : 'apachectl -v'; $regex = '/Apache\/(\d{1,2}\.\d{1,2}\.\d{1,2})/'; switch(true) { case (preg_match($regex, getenv('SERVER_SOFTWARE'), $matchAry)): case (function_exists('apache_get_version') && preg_match($regex, apache_get_version(), $matchAry)): case (preg_match($regex, shell_exec($shell), $matchAry)): return $matchAry[1]; default: return false; } }
使い方
$version = apacheVersion(); // string(6) "2.4.39" //-- Apacheをソースからビルドした環境やWindows環境等で //-- Apacheのバージョンを取得するコマンドを指定したい時 apacheVersion('C:\apache\bin\httpd.exe -v');
ソースの解説
function apacheVersion($pShell = null) { //-- Apacheのバージョンを取得するためのコマンド $shell = (isset($pShell)) ? $pShell : 'apachectl -v'; //-- Apacheのバージョンを取得するための正規表現 $regex = '/Apache\/(\d{1,2}\.\d{1,2}\.\d{1,2})/'; switch(true) { //-- 1.環境変数からの取得を試みる case (preg_match($regex, getenv('SERVER_SOFTWARE'), $matchAry)): //-- 2.apache_get_version()での取得を試みる case (function_exists('apache_get_version') && preg_match($regex, apache_get_version(), $matchAry)): //-- 3.コマンドでの取得を試みる case (preg_match($regex, shell_exec($shell), $matchAry)): return $matchAry[1]; //-- バージョン取得失敗 default: return false; } }
なぜ三段構えになっているか
1.環境変数からの取得を試みる
この方法では、例えば PHP を CLI 版で動作させている時は取得できません。('SERVER_SOFTWARE' は定義されません。)
また、この方法で取得できるのは、Apache の
ServerTokensの設定が、FullOSMinimalの時のみです。公開環境では
Prodを設定し、HTTP ヘッダに Apache のバージョンが公開されないようにするのが普通です。ServerTokens Prodこの設定の場合、
getenv('SERVER_SOFTWARE')には'Apache'という文字列しか入りません。2.apache_get_version()での取得を試みる
基本的に 1 と同じですが、せっかく用意されている関数ですので…。
3.コマンドでの取得を試みる
…というわけで、最終手段として Apache に直接聞いちゃえ!って事です。
- 投稿日:2019-05-30T10:43:30+09:00
Heroku logs に var_dump()
Heroku上のPHPアプリでprintデバッグする場合
error_log()で出力するのがお手軽https://devcenter.heroku.com/articles/php-logging
問題点
けれども、配列の中身が見たくて
$a = array(1, 2, array("a", "b", "c")); error_log('$a:'); var_dump($a);や
error_log('$a:' . var_dump($a));としても
↓のようになって、配列の中身はHeroku logsに出力されない$a:原因
var_dump()は返り値が無いので、error_log()に出力内容が渡されていないから
対策
var_dumpの出力を変数に格納し、その変数をerror_log()に渡す
// var_dumpを文字列に変換する関数を作成 function get_str_var_dump($var){ ob_start(); // バッファリングON var_dump($var); $bar = ob_get_contents(); // バッファの内容を変数に格納 ob_end_clean(); // バッファを消去してバッファリングOFF return $bar; } $a = array(1, 2, array("a", "b", "c")); // 配列$aをget_str_var_dump()で文字列に変換してからerorr_log()に渡す error_log('$a:' . get_str_var_dump($a));↓ のように出力できた
$a:array(3) { [0]=> int(1) [1]=> int(2) [2]=> array(3) { [0]=> string(1) "a [1]=> string(1) "b [2]=> string(1) "c } }参考
https://macocci7.exblog.jp/18510693/
https://www.php.net/manual/ja/function.var-dump.php
https://www.php.net/manual/ja/function.ob-start.php
- 投稿日:2019-05-30T09:10:13+09:00
php-master-changes 2019-05-29
今日は JIT で optimization_level を考慮するようにする修正、多数のブロックがある関数を JIT コンパイルしないようにする修正、FFI の特定テストでの JIT 無効化、travis での JIT 有効化、opcache のメモリリークの修正と func_info の更新、幾つかの局所最適化、run-tests.php で実行許可ビットが外れていたことの修正、マクロの定義間違いの修正、無効化指定の関数で ZEND_ACC_HAS_RETURN_TYPE を保持しないようにする修正、不使用変数の削除、DatePeriod のプロパティアクセスのテスト追加と get_property_ptr_ptr ハンドラの追加、set オブジェクトハンドラの削除、API バージョンの更新、escapeshellarg() と escapeshellcmd() へ NUL 文字含んだ引数を与えた際 TypeError を投げるようにする修正があった!
2019-05-29
nikic: Respect optimization_level when running JIT inference
- https://github.com/php/php-src/commit/4d1d5babde725febc5fdc7a7ccf576f3d0e3c099
- ext/opcache/jit で、optimization_level を考慮してデフォルトでは安全でない型推論を行わないよう修正
- IGNORE_OVERLOADING が無効になり opcache.optimization_level=-1 すれば有効化できるもよう
dstogov: Replace ZVAL_COPY() and ZVAL_COPY_VALUE() for IS_OBJECT by cheaper macros
- https://github.com/php/php-src/commit/83804519dffcbb23ef689b37816ee28f2c3192e0
- [7.4~]
- IS_OBJECT で ZVAL_COPY()、ZVAL_COPY_VALUE してた箇所の局所最適化
duncan3dc: Restore the execute bit for run-tests.php
- https://github.com/php/php-src/commit/72c330f1e6000e6b52f92c13c42bf9c620c20ddf
- run-tests.php で、実行許可ビットがなんか外れちゃってたのを戻した
dstogov: Avoid cold code duplication
- https://github.com/php/php-src/commit/8c0b0c6a1e6868ec905ce9c4e8313a67669829c1
- [7.4~]
- メモリ確保解放系のコールドコードを関数にまとめ局所最適化
weltling: These macros should not expect any argument
- https://github.com/php/php-src/commit/1a4ace05aedf5e9413eb089f5415dfabfe638196
- 引数をとらないマクロ RETVAL_EMPTY_ARRAY()、RETURN_EMPTY_ARRAY() がとるかのように書かれてたのを修正
weltling: Fix conditional compilation
- https://github.com/php/php-src/commit/08a0030b33a46849ddda8bd962a6b05db0750c4a
- [7.4~]
- メモリ確保解放系の関数追加部分について条件コンパイルの修正
krakjoe: disabled functions must not have return type
- https://github.com/php/php-src/commit/7821cc3b9f51d12f2cf391e191fef1f591cb7f35
- [7.2~]
- 無効化指定の関数については ZEND_ACC_HAS_RETURN_TYPE をクリアするよう修正
carusogabriel: Remove unused variable
dstogov: zend_do_fcall_overloaded() doesn't have to be exported
- https://github.com/php/php-src/commit/0d102515bf4adf102ebb889f42c86d946f0000b8
- [7.4~]
- zend_do_fcall_overloaded() を内部リンケージにしてコールドコード指定に修正
duncan3dc: Add tests for DatePeriod properties
- https://github.com/php/php-src/commit/5d67271db07b94321cd57c5679bc6ab02070bc11
- [7.2~]
- ext/date で、DatePeriod のプロパティアクセスのテストを追加
nikic: Specify get_property_ptr_ptr handler for DatePeriod
- https://github.com/php/php-src/commit/3bd5b83615d47e480840d50fcaab31a5463cb314
- [7.4~]
- ext/date で、7.4 から指定の必要な get_property_ptr_ptr のハンドラを追加
- NULL を返して read_property へフォールバックするだけの実装
nikic: Remove set() object handler
- https://github.com/php/php-src/commit/31a516cf967e7558f0e06c2390fa9521309ed8b4
- set オブジェクトハンドラの削除
- 代入演算子のオーバーロードに使われていたがほぼ利用されてなかった
derickr: Bump API numbers
- https://github.com/php/php-src/commit/8ec0cf8be72b8b7d025443a9b9510d2fbe3e4f99
- [7.4~]
- API バージョンの更新
dstogov: Mark "cold" functions
- https://github.com/php/php-src/commit/e14d77335c5827f1a0445141efd58440a1e65db7
- [7.4~]
- ZEND_COLD 指定をいくらか追加
nikic: Don't JIT functions with many blocks
- https://github.com/php/php-src/commit/b7a6430a52da182646844860a03fc6befbac8012
- ext/opcache/jit で、多数のブロックがある関数を JIT コンパイルしないよう修正
- 解析時の一部再帰的処理でのスタックオーバーフローの回避らしい
nikic: Disable JIT for ext/ffi/tests/200.phpt
- https://github.com/php/php-src/commit/c7a67c6dcef5c1d07f2cdbdf11ba25166da2d5f0
- ext/ffi で、特定テストで JIT の無効化
- JIT では zend_write が実行時に変更されないことを仮定しているため
- こんなことできる FFI やべーだろ案件のため、このテストでは単に無効化でいいか、という
dstogov: zend_assign_to_variable() optimization
- https://github.com/php/php-src/commit/b06f05bf4782c4c7110f9d974db1b70c4cda36c0
- [7.4~]
- zend_assign_to_variable() の局所最適化
- たぶん型付き参照への代入のパスに入った時の分岐予測ヒントあたりで違いが出るのだろうという気はするけどよく分からず
nikic: Enable JIT in Travis build
- https://github.com/php/php-src/commit/e94a71b7f1539117e7ee20945127937c4ae6ce9a
- travis の設定で JIT を有効化
nikic: Update more func info information for ext/standard
- https://github.com/php/php-src/commit/a1a8d144854acb1c891cf0c21abb0f612b1d8de7
- ext/opcache で、func_info の更新
nikic: SCCP: Fix leak when determining TYPE_CHECK from type info
- https://github.com/php/php-src/commit/61a38bb2743ef2e76278aeeec9ec486b75e94485
- [7.4~]
- ext/opcache で、SCCP 最適化器のメモリリークの修正
- ZEND_TYPE_CHECK を ZEND_FREE に置き換えるとかやってるよーに見える
nikic: escapeshellarg/escapeshellcmd: Throw TypeError instead of E_ERROR
- https://github.com/php/php-src/commit/07fae1fd6efec09dcd928760147682cd6a6aa354
- escapeshellarg() と escapeshellcmd() について、NUL 文字含んだ引数を与えた際 E_ERROR にしていたのを TypeError を投げるよう修正
- 投稿日:2019-05-30T00:12:31+09:00
laravelでURLを作成する便利な関数(route()・action())いいなーと思っていたら、はまった話
route()・action()はどちらもURLを作成するときにすごく便利です。
route('sample.index'); //こちらは、routes/web.phpでnameを指定する必要があります。 action('SampleController@index');どちらも同様のURLを作成してくれます。第二引数で、パラメータを渡すことができます。
Bladeのほうで、利用するときは、旧型の書き方と比べると可読性が全然違います。旧型
{{Form::open(['url' => 'http://sample/index?id='. $data['id']. '&name='. $data['name'])}}route()・action()利用時
url属性を使用した場合
{{Form::open(['url' => route('sample.index', [$data])])}} {{Form::open(['url' => action('SampleController@index', [$data])])}}LaravelのBladeには、routeとactionの属性が用意されています(パラメータがない場合は利用する)
(こちらの形でも、input hiddenを使えば、パラメータを渡すことは可能ですが、個人的には、すべてurl属性を使って統一するほうが見やすい気がします。){{Form::open(['route' => 'sample.index'])}} {{Form::open(['action' => 'SampleController@index])}}Formにroute関数を使用して、特定の場合、思った挙動をしなくなる話
当然と言われれば、それまでの話なのですが、URLにidを埋め込んで、そのidに、/を入れたときに、思った通りの挙動をしません。例をあげてみます。
routes/web.phpRoute::get('/test/{id}/index', 'TestController@index')->name('test.index');idごとのデータのindexメソッドの処理がはしる想定のルートです。
TestController.phppublic function index(Request $request, $id) { dd($id); }引数で、idを受け取ります。それでは、bladeを編集します。
test.blade.php{{Form::open(['url' => route('test.index', ['id' => '1']), 'method' => 'get'])}} {{Form::submit('送信')}} {{Form::close()}}まずは、idに1をいれて、ボタンを押下してみます。
想定通り、1が表示されました。それでは、/をいれてみます。
test.blade.php{{Form::open(['url' => route('test.index', ['id' => '/']), 'method' => 'get'])}} {{Form::submit('送信')}} {{Form::close()}}/を入れて試してみます。404エラーがでました。URLをみると、///となっており、URLがおかしくなっています。
対処法
本来、/はURLの区切り、?はパラメータを渡すときにURLの大切な役を担っています。それを、URLのパラメータとして使用するためには、エンコードする必要があります。
routes/web.phpRoute::get('/test/{id}/index', 'TestController@index')->name('test.index')->where('id', '(.*)');できました。?をパラメータに使いたい場合は、エンコードされていたらそのまま使えますが、されていなかったら、urlencode('?')などでエンコードしてから、パラメータとして使用しましょう。
まとめ
パラメータに/や?を使わないようするのが一番いいと思います



