カスタムバリデーション (3) 既存バリデーションの置き換え

Laravelには最初から利用可能なバリデーションルールが多数存在していますが、そのいくつかは実用にならなかったり、自分好みに挙動を変えたりしたいこともあります。

CustomValidatorクラスは標準Validatorを継承していますので、これらを置き換えて上書きすることが可能です。

vendor/laravel/framework/src/Illuminate/Validation/Validator.php

ここから関数宣言をコピーして、前回作成したCustomValidatorクラスのファイルに貼り付けて編集します。引数はそれぞれの関数によって異なりますし、宣言が public ではなく protected であることに注意してください。

email

標準のemailバリデーションは実在してるメールアドレスがエラー判定になることがあります。これを解決するために正規表現による判定に置き換えてみたものです。

    /**
     * email
     *
     * @param string $attribute
     * @param string $value
     * @return true
     */
    protected function validateEmail($attribute, $value)
    {
        return (preg_match("/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,10})$/i", $value));
    }

 

管理画面では、メール送信者の指定などで名前付きメールアドレスの入力を容認する場面もあります。ついでに email_with_name を作成しておきましょう。

    /**
     * email_with_name
     *
     * @param string $attribute
     * @param string $value
     * @return true
     */
    public function validateEmailWithName($attribute, $value)
    {
        if (preg_match('/<(.*)>$/', $value, $m)
        {
            $value = $m[1];
        }

        return $this->validateEmail($attribute, $value);
    }

 

alpha, alpha_dash, alpha_num

これらアルファベット系の標準バリデーションは、全角英数字の文字コードを通します。

半角のasciiコードだけの入力許可に絞るため、これらも正規表現によるバリデーションルールに置き換えます。

/**
 * alpah
 *
 * @param string $attribute
 * @param string $value
 * @return true
 */
protected function validateAlpha($attribute, $value)
{
    return (preg_match("/^[a-z]+$/i", $value));
}

/**
 * alpah_dash
 *
 * @param string $attribute
 * @param string $value
 * @return true
 */
protected function validateAlphaDash($attribute, $value)
{
    return (preg_match("/^[a-z0-9_-]+$/i", $value));
}

/**
 * alpah_num
 *
 * @param string $attribute
 * @param string $value
 * @return true
 */
protected function validateAlphaNum($attribute, $value)
{
    return (preg_match("/^[a-z0-9]+$/i", $value));
}

ただし、ユーザが入力した全角英数に対してただエラーを返すようなユーザーインターフェースは褒められたものではありませんね。

入力を受け付けてからphpで半角に変換するという方法もありますが、私たちはjQueryスクリプトで入力前に変換する方法を選択しています。

jQueryスクリプトの例:

			var toHankaku = function (strVal){
				// 半角変換
				var halfVal = strVal.replace(/[!-~]/g, function(tmpStr) {
					// 文字コードをシフト
					return String.fromCharCode(tmpStr.charCodeAt(0) - 0xFEE0);
				});

				// 文字コードシフトで対応できない文字の変換
				halfVal = halfVal.replace(/”/g, "\"")
					.replace(/[ーー―-‐]/, "-")
					.replace(/’/g, "'")
					.replace(/‘/g, "`")
					.replace(/¥/g, "\\")
					.replace(/ /g, " ")
					.replace(/?/g, "~");

				return halfVal;
			};

			$("input.en").change(function() {
				var $this = $(this);
				$this.val(toHankaku($this.val()));
			});

カスタムバリデーション (2) CustomValidatorを追加

カスタムバリデーションのクラスを追加するには、サービスプロバイダーで次のようにクラスを登録します。

追加するクラスの名前や位置はどのようなものでもかまいせん。ここでは、ディレクトリパス app/Services に CustomVaidator.phpを作成し、AppServiceProvider に登録することにします。
続き “カスタムバリデーション (2) CustomValidatorを追加”

routesを使いこなす(4)routeを名付ける

Laravelでは、routeに名前を付けることができます。いったいそれがどうした?と思いますが、これができることで便利なことが増えます。

まず、routeの名前の付け方から、


Route::get('admin/ranking/download', 'RankingController@download');

routes.phpに指定して、

php artisan route:list

を実行すると、

+--------+-----------+-------------------------+------------------------+-------------------------------------------------------+
| Domain | Method    | URI                     | Name                   | Action                                                |
+--------+-----------+-------------------------+------------------------+-------------------------------------------------------+
|        | GET|HEAD  | admin/ranking/download  |                        | App\Http\Controllers\Admin\RankingController@download |

を出力します。3列名のNameの列に注目してください。

今は空ですね。

しかし、


Route::get('admin/ranking/download', 'RankingController@download')->name('admin.ranking.download');

とすると、

+--------+-----------+-------------------------+------------------------+-------------------------------------------------------+
| Domain | Method    | URI                     | Name                   | Action                                                |
+--------+-----------+-------------------------+------------------------+-------------------------------------------------------+
|        | GET|HEAD  | admin/ranking/download  | admin.ranking.download | App\Http\Controllers\Admin\RankingController@download |

admin.ranking.downloadと名前が付きます。

現在は、URIのスラッシュ(/)をピリオド(.)に置き換えたフォーマットですが、admin:ranking_downloadでも、admin::rankingdownloadでもOKです。

さて、routeにresourceを使用するときはどうなるのでしょう?

例えば、

Route::resource('product', 'ProductController');

は、

+--------+-----------+------------------------------------+------------------------+-----------------------------------------------------------------------+-----------------+
| Domain | Method    | URI                                | Name                   | Action                                                                | Middleware      |
+--------+-----------+------------------------------------+------------------------+-----------------------------------------------------------------------+-----------------+
|        | POST      | admin/product                      | admin.product.store    | App\Http\Controllers\Admin\ProductController@store                    | web             |
|        | GET|HEAD  | admin/product                      | admin.product.index    | App\Http\Controllers\Admin\ProductController@index                    | web             |
|        | GET|HEAD  | admin/product/create               | admin.product.create   | App\Http\Controllers\Admin\ProductController@create                   | web             |
|        | GET|HEAD  | admin/product/{product}            | admin.product.show     | App\Http\Controllers\Admin\ProductController@show                     | web             |
|        | DELETE    | admin/product/{product}            | admin.product.destroy  | App\Http\Controllers\Admin\ProductController@destroy                  | web             |
|        | PUT|PATCH | admin/product/{product}            | admin.product.update   | App\Http\Controllers\Admin\ProductController@update                   | web             |
|        | GET|HEAD  | admin/product/{product}/edit       | admin.product.edit     | App\Http\Controllers\Admin\ProductController@edit                     | web             |
+--------+-----------+------------------------------------+------------------------+-----------------------------------------------------------------------+-----------------+

と自動で名前を付けてくれます。

routeに名前が付いたところで、どう使用するか見てみましょう。

echo route('admin.ranking.download');

は、

http://localhost/admin/ranking/download

となります。もちろん、localhostはライブ環境では実際のドメイン名となります。

ということは、

echo url('admin/ranking/download');

と同じになります。

引数があるときは、

echo route('admin.product.edit', 12);
echo url('admin/product', [12, 'edit']);

の出力は、両方とも、

http://localhost/admin/product/12/edit

となりますが、名前付きの方がわかりやすいですね。

このroute()は、

return redirect()->route('admin.product.show', 12);

のようにリダイレクトや、


{!! Form::open(['route' => ['admin.product.store'], 'method' => 'post']) !!}

のようにテンプレートでも使用可能です。

もちろん、名前付きのrouteをプログラムで使用するなら、そのrouteのURIを変えても何もプログラムで変更は要らないことになります。便利ですね。

さらに、URIに比べて比較的扱いやすい文字列なので、名前付きのrouteに対してユーザーの権限をDBで定義すれば、例えば、ログインしたユーザーの役割により、特定のrouteを実行するかどうかの権限の判断にも使用可能です。将来、この連載で扱う予定のトピックです。

カスタムバリデーション(1)Validatorファサードのextend

はじめまして。ブログ主筆khino氏と同じプロジェクトで仕事をしてます。
彼とは別テーマを平行して掲載しますので、これまで順番に読み進めていた方にはちょっと読みにくくなるかもしれませんが、ご容赦ください。

私の最初のテーマはカスタムバリデーションルールです。
このシリーズでは、Validatorファサードの基本的な使い方から始めて、より複雑なルールの定義の仕方や、laravel 5.2で追加された配列定義のカスタムバリデーションまで紹介する予定です。
続き “カスタムバリデーション(1)Validatorファサードのextend”

routesを使いこなす(1)resourceを使う

私が開発・管理しているプロジェクトのひとつは、もともとは過去に人気があったCodeIgniterで書かれたもの。過去2年の間に、それをLaravelのバージョン4で書き直し、さらに更新して現在はLaravelのバージョン5.2となっています。

それゆえに、最初のLaravelを使っての書き換えは、Laravelを勉強しながの書き換えで、知らないことが多く、Route::controllerを多用していました。
続き “routesを使いこなす(1)resourceを使う”

親子関係のテーブルでのクエリーの作成(Eloquent編)

Laravel以前は、ほぼコードにSQL文を埋め込んでいたので、Eloquentよりクエリビルダーの方が馴染みあります。特に複数のDBテーブルをjoinした検索などには。

しかし、各Modelにおいてリレーションを定義していると、それを使用しないのがもったいないように思えてきます。

クエリビルダーでできることをEloquentではどうやるのか、興味ありありになってきました。
続き “親子関係のテーブルでのクエリーの作成(Eloquent編)”

Eloquentでカウントするときの注意

Eloquentのcount()の関数を使用して、DBのレコード数を数える作業はよく起こります。

例えば、前回の画像の件では、商品productのレコード1に対して商品画像product_imageレコードがが複数あるという、1対多の関係。そこでは、商品を削除するときに商品画像がないかをチェックする必要あります。画像のレコードがあるなら、削除を拒否あるいはユーザーに削除してよいか尋ねるということになります。

この場合は、商品画像があるかないかは、count()するのが一番。しかし、Eloquentではいろいろなカウントのコードの仕方があります。

今回は、これを説明するために、コントローラに特別にメソッドを作成してみました。
続き “Eloquentでカウントするときの注意”