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

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

ただいまの
回答率

90.34%

  • CakePHP

    2394questions

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

cake3 NGワード設定

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 569

sbc

score 15

前提・実現したいこと

・登録フォームを用意(対象の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/

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/08 14:44 編集

    なるほど。バリデート関数内でDBにアクセスするのはとてもスマートでいいですね!
    是非参考にさせて頂きます。

    ちなみにここで設定したmassageはどのタイミングで表示されるのでしょうか?
    debugで見てみるとerrors()の中には `name = "The provided value is invalid"` とあります。

    バリデーションが実行されるのはEntityの作成時だと思いますが、今回はアソシエーションしている別Tableでこのバリデーションを行っているので、newEntityをするTableには含まれておらず、バリデーションはかかっているようなのですがメッセージが表示されません。

    キャンセル

  • 2017/02/08 15:27 編集

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

    キャンセル

  • 2017/02/08 16:29

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

    キャンセル

  • 2017/02/08 19:28

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

    キャンセル

  • 2017/02/09 14:19

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

    キャンセル

  • 2017/02/09 14:26

    > returnされないパスとはどういったものでしょうか?

    関数がreturnで終わっていないものです。例えば以下の関数だと$isHogeがfalseだと関数の最後までいきますが、関数の最後でreturnしていないとreturn nullと同じことになります。
    function() {
    if($isHoge) {
    return false;
    }
    }

    キャンセル

  • 2017/02/09 14:28

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

    キャンセル

  • 2017/02/09 15:50

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

    キャンセル

  • 2017/02/09 16:04 編集

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

    キャンセル

  • 2017/02/09 16:11

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

    キャンセル

  • 2017/02/09 16:20

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

    キャンセル

  • 2017/02/09 16:20

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

    キャンセル

  • 2017/02/09 16:21

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

    キャンセル

  • 2017/02/09 16:30

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

    キャンセル

  • 2017/02/09 16:31

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

    キャンセル

  • 2017/02/09 16:49

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

    キャンセル

  • 2017/02/09 17:02

    ざっと見た感じよさそうですけどね。erorr()があった場合、save()はしない方がいいと思いますが、saveは失敗するんですよね?

    アソシエーション以外のデータのエラーメッセージはでるのでしょうか
    バリデート失敗時には、入寮した値はinputに入っていますか

    キャンセル

  • 2017/02/09 17:23

    できました!
    原因はTemplateのcreate()第一引数の記述かと思われます。
    $this->Form->create('member')と書いていたのですが
    $this->Form->create($member)に修正することで動作しました。
    本文のコードを動作確認状態に修正してあります。

    errorがあった場合はsaveは失敗するのでリダイレクトもされませんが、この書き方は良くないでしょうか。

    修正前の時点ではアソシエーション以外のデータのエラーメッセージも出ませんでした。
    バリデート失敗時にはinputに値は入っていました。

    キャンセル

  • 2017/02/09 17:34

    なるほど... $memberが正しいですね。解決して良かったです!

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

    キャンセル

  • 2017/02/09 18:53

    なるほどです。。
    errorのあとはreturn ;で終わらせることにします。

    長々とお付き合い頂きありがとございました!。。

    キャンセル

同じタグがついた質問を見る

  • CakePHP

    2394questions

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