質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

Q&A

解決済

1回答

2316閲覧

cake3 NGワード設定

sbc

総合スコア21

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

0グッド

0クリップ

投稿2017/02/08 04:51

編集2017/02/09 08:17

###前提・実現したいこと

・登録フォームを用意(対象のinputはnameとかで)
・ng_wordテーブルに設定した言葉をバリデーションしたい

1.テーブルに単語を登録
2.ControllerのinitializeでTableRegistryを使用してng_wordEntityを取得
3.Actionで $this->set('ngword', $this->ngwords->find())

Controller

public function register($lang = null) { $lang = ($lang === null) ? 'ja' : $lang; $dataMaster = new DataMaster(); $this->set('Countries', $dataMaster->getAllCountries($lang)); $this->set('Languages', $dataMaster->getAllLanguages($lang)); $this->set('Genders', $dataMaster->getAllGenders($lang)); if ($lang === 'ja') { $this->set('Prefectures', $dataMaster->getAllPrefectures($lang)); }else{ $this->set('Prefectures', false); } $member = $this->Member->newEntity(); if ($this->request->is('post')) { $member = $this->Member->newEntity($this->request->data, [ 'associated' => ['MemberDetail'] ]); if ($member->errors()){ $this->Flash->error(__('The member could not be saved. Please, try again.')); } if ($this->Member->save($member)) { $this->Flash->success(__('The member has been saved.')); return $this->redirect(['action' => 'login']); } } $this->set(compact('member')); $this->set('_serialize', ['member']); }
$ngWords = $this->ngwords->find(); foreach ($ngWords as $row){ $word[] = $row->word; } $this->set('ngwords', $word);

Table

public function validationDefault(Validator $validator) { $validator ->allowEmpty('id', 'create'); $validator ->allowEmpty('nickname') ->add('nickname', [ 'ngword' => [ 'rule' => function($value, $context){ return !TableRegistry::get('ng_word')->exists(["'{$value}' LIKE concat('%', word, '%')"]); }, 'massage' => '「おなまえ」に不適切な語句が含まれています' ] ]); $validator ->integer('gender') ->notEmpty('gender'); $validator ->date('birthday') ->allowEmpty('birthday'); $validator ->integer('country') ->allowEmpty('country'); $validator ->integer('prefecture') ->allowEmpty('prefecture'); $validator ->integer('language') ->allowEmpty('language'); $validator ->allowEmpty('created_by'); $validator ->dateTime('created_at'); $validator ->allowEmpty('updated_by'); $validator ->dateTime('updated_at'); return $validator; }

Template

<div class="member form large-9 medium-8 columns content"> <?= $this->Form->create($member) ?> <fieldset> <legend><?= __('新規会員登録') ?></legend> <p>全項目入力して下さい</p> <?php echo $this->Form->input('member_detail.0.nickname', ['label' => __('なまえ')]); echo $this->Form->input('member_detail.0.gender', ['label' => __('性別'), 'type' => 'radio', 'options' => $Genders]); echo $this->Form->input('member_detail.0.birthday', ['label' => __('生年月日'), 'type' => 'date', 'dateFormat' => 'YMD', 'monthNames' => false, 'maxYear' => date('Y'), 'minYear' => 1850, 'empty' => '---']); echo $this->Form->input('member_detail.0.country', ['label' => __('国籍'), 'type' => 'select', 'options' => $Countries]); if ($Prefectures) { echo $this->Form->input('member_detail.0.prefecture', ['label' => __('都道府県'), 'type' => 'select', 'options' => $Prefectures]); } echo $this->Form->input('member_detail.0.language', ['label' => __('言語'), 'type' => 'select', 'options' => $Languages]); echo $this->Form->input('mail_address', ['label' => __('メールアドレス'), 'type' => 'email']); echo $this->Form->input('login_id', ['label' => __('ログインID'), 'type' => 'text']); echo $this->Form->input('login_password', ['label' => __('パスワード'), 'type' => 'password']); echo $this->Form->hidden('is_active', ['default' => 1]); echo $this->Form->hidden('is_deleted', ['default' => 0]); ?> </fieldset> <?= $this->Form->button(__('確認')) ?> <?= $this->Form->end() ?> </div>

ここからどうして良いか分かりません。

カスタムバリデーションの作成や取得したデータをそこに反映させる方法等・・

###補足情報(言語/FW/ツール等のバージョンなど)
php7.1.1 / cake PHP3.3.12/

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

カスタムバリデートで、バリデート関数内でng_wordテーブルにアクセスすればいいと思います。
以下、サンプルです。

php

1 public function validationDefault(Validator $validator) { 2 $validator 3 ->add('name', [ 4 'ngword' => [ 5 'rule' => function($value, $context) { 6 return !TableRegistry::get('ng_word')->exists(["'{$value}' LIKE concat('%', word, '%')"]); 7 }, 8 'message' => 'NGワードが含まれています' 9 ], 10 ]); 11 return $validator; 12 }

投稿2017/02/08 05:32

popobot

総合スコア6586

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sbc

2017/02/08 05:54 編集

なるほど。バリデート関数内でDBにアクセスするのはとてもスマートでいいですね! 是非参考にさせて頂きます。 ちなみにここで設定したmassageはどのタイミングで表示されるのでしょうか? debugで見てみるとerrors()の中には `name = "The provided value is invalid"` とあります。 バリデーションが実行されるのはEntityの作成時だと思いますが、今回はアソシエーションしている別Tableでこのバリデーションを行っているので、newEntityをするTableには含まれておらず、バリデーションはかかっているようなのですがメッセージが表示されません。
popobot

2017/02/08 06:55 編集

手元の環境ではちゃんとメッセージ出ましたけどね。他のバリデートが先に引っかかったりしてないですかね。アソシエーションでもFormヘルパーを使っていればメッセージも表示されるはずですが
sbc

2017/02/08 07:29

他には引っかかるバリデートはありませんでした。 気になっているのは$member->errors()で取れるエラーメッセージがカスタムで設定したmassageではなくvalidator.phpの_processRulesに記載されているものになっていることです。
popobot

2017/02/08 10:28

このメッセージはバリデーションでnullを返すと表示されます。もしくは何もreturnしないパスがあるのかと
sbc

2017/02/09 05:19

ng_wordのバリデーション時にはfalseを返します。 returnされないパスとはどういったものでしょうか?
popobot

2017/02/09 05:26

> returnされないパスとはどういったものでしょうか? 関数がreturnで終わっていないものです。例えば以下の関数だと$isHogeがfalseだと関数の最後までいきますが、関数の最後でreturnしていないとreturn nullと同じことになります。 function() { if($isHoge) { return false; } }
popobot

2017/02/09 05:28

モデルのバリデートの定義部分を質問に記載していただけると、何かわかるかもです。
sbc

2017/02/09 06:50

バリデートの定義部分を追記致しました。
sbc

2017/02/09 07:10 編集

nicknameのバリデーションではfalseが返って来ているのですが、errorのmessageに指定した文字は入っていないです。
sbc

2017/02/09 07:11

失礼しました。typoです。「massage」でかいていました。 修正したところ$member->errors()のmessageには入っていますが、ブラウザ表示は未だにされません。
popobot

2017/02/09 07:20

表示はテンプレート側なので、テンプレート側のコードをみないとわかりません。
sbc

2017/02/09 07:20

こちら$member->errors()の中身を指定して$this->Flash->error()に入れることでエラーメッセージを表示することは出来ました。 しかし、一度に複数のバリデーションエラーが発生した時に対応できません。 どうするのが一般的なのでしょうか。
popobot

2017/02/09 07:21

普通、テンプレート側でFormヘルパーのcreate()を実行する際に、第一引数にバリデートしたエンティティを含むデータを渡せばいいだけのはずです。
sbc

2017/02/09 07:30

上記$member->errors()をTemplate側に渡してループさせて一括表示することで対応しようとしましたが、カスタムのバリデーションメッセージとデフォルトの_emptyなどのメッセージの格納されている配列構造が違うため苦戦しています。何かいい方法はありませんでしょうか。。
sbc

2017/02/09 07:31

すみません。↑返信を見る前に書いてしまいました。 createの第一引数に入れる方法を試してみます。
sbc

2017/02/09 07:49

Controller及びTemplateを追記しました。 この状態でも駄目なのですがどこがおかしいでしょうか・・
popobot

2017/02/09 08:02

ざっと見た感じよさそうですけどね。erorr()があった場合、save()はしない方がいいと思いますが、saveは失敗するんですよね? アソシエーション以外のデータのエラーメッセージはでるのでしょうか バリデート失敗時には、入寮した値はinputに入っていますか
sbc

2017/02/09 08:23

できました! 原因はTemplateのcreate()第一引数の記述かと思われます。 $this->Form->create('member')と書いていたのですが $this->Form->create($member)に修正することで動作しました。 本文のコードを動作確認状態に修正してあります。 errorがあった場合はsaveは失敗するのでリダイレクトもされませんが、この書き方は良くないでしょうか。 修正前の時点ではアソシエーション以外のデータのエラーメッセージも出ませんでした。 バリデート失敗時にはinputに値は入っていました。
popobot

2017/02/09 08:34

なるほど... $memberが正しいですね。解決して良かったです! > errorがあった場合はsaveは失敗するのでリダイレクトもされませんが、この書き方は良くないでしょうか。 別に大丈夫ですが、error()があったら$this->Flash->error()の後にreturnしちゃった方がわかりやすいかと
sbc

2017/02/09 09:53

なるほどです。。 errorのあとはreturn ;で終わらせることにします。 長々とお付き合い頂きありがとございました!。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問