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

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

ただいまの
回答率

90.01%

PHPでの少し複雑な条件判定

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 608

YutaNkai

score -68

現在phpで大学受験のシステムを課題作成しています。
ユーザー(受験者が)受検したい学科などを選択し、個人情報、支払い情報を入力する。というのがシステムの流れです。

現在担当しているのが、ユーザー(受験者が)選択した、試験会場や学科がルールに沿っているかを確認する条件分岐です。

条件分岐の詳細

ユーザー(受験者)は画面に表示される項目を選択します。

★ユーザー(受験者)選択の順序

試験グループ → 試験募集区分 → 受験日 → 学科、試験会場

★試験グループについて

イメージとしては「AO入試」、「一般入試」、「帰国子女枠」などです。
今回は画面には一つ(一般入試)しか表示されておらず、ユーザー(受験者)には選択肢はありません。

★試験募集区分について

試験グループ(一般入試)を選択後に画面が遷移し、
画面には「前期」「中期」の二つが表示されています。

★受験日について

試験募集区分を選択すると、ドロップダウンで選択できる受験日が表示されます。
「前期」→ 07/08 or 07/09
「中期」→ 12/10 or 12/11
が選択肢となっています。

★学科、試験会場について

受験日を選択すると選択可能な学科と試験会場が表示されます。
前期、中期や選択肢した受験日に関わらず

学科は「経済学部」と「経営学部」、試験会場は「東京」「大阪」「福岡」が選択できます。

★エラーを表示させる条件

同一試験募集区分で複数受験する場合 ↓
例)前期 → 07/08 と 前期 → 07/09 を受験
例)中期 → 12/10 と 中期 → 12/11 を受験

①試験会場は両日程とも同じでなけらばならない。
②学科は両日程とも同じでなけらばならない。

エラーにしたいのはこの条件に反した場合のみです。

前期 → 07/08 → 経済学部、東京 と 前期 → 07/09 → 経済学部、大阪 は試験会場エラーですが
前期 → 07/08 → 経済学部、東京 と 中期 → 12/10 → 経済学部、大阪 は試験会場エラーになりません。

前期 → 07/08 → 経済学部、東京 と 前期 → 07/09 → 経営学部、東京 は学科エラーですが
前期 → 07/08 → 経済学部、東京 と 中期 → 12/10 → 経営学部、東京 は学科エラーになりません。

値を定義しているphpファイル

/*定義①

試験グループ 一般入試 EXAMG00001-0001
試験募集区分 前期 EN00000-101 中期 EN00000-102
試験日 07/08 EN10000-701 07/09 EN10000-702 12/10 EN10001-701 12/11 EN10001-702
試験会場 東京 EN20000-101 大阪 EN20000-102 福岡 EN20000-103
学科 経済 EN30000-001 経営 EN30000-002

定義②

試験日07/08 SCD000-001
試験日07/09 SCD000-002
試験日12/10 SCD000-003
試験日12/11 SCD000-004

試験会場 東京 PLA000-001
試験会場 大阪 PLA000-002
試験会場 福岡 PLA000-003

学科 経済学部 CRS000-001
学科 経営学部 CRS000-002

定義①と②を結びつけるファイルがあり以下の様に定義されています。
試験日グループと試験募集区分についてはどの様に定義されていたかは覚えていません。

*/

$image =
[

//試験グループ
'EXAMG00001-0001' => 'something',

//試験募集区分
//前期
'EN00000-101' => 'something',
//中期
'EN00000-102' => 'something',

//試験日
//07/08
'EN10000-701' => 'SCD000-001',
//07/09
'EN10000-702' => 'SCD000-002',
//12/10
'EN10001-701' => 'SCD000-003',
//12/11
'EN10001-702' => 'SCD000-004',

//試験会場
//東京
'EN20000-101' => 'PLA000-001',
//大阪
'EN20000-102' => 'PLA000-002',
//福岡
'EN20000-103' => 'PLA000-003',

//学科
//経済学部
'EN30000-001' => 'CRS000-001',
//経営学部
'EN30000-002' => 'CRS000-002',

];

POSTされる値をphpファイルに作成

/*
ユーザー(受験者)は以下の4つの試験を受験すると選択しました。

希望試験:
一般入試 → 前期 → 07/08 → 東京、経済学部
一般入試 → 前期 → 07/09 → 大阪、経済学部
一般入試 → 中期 → 12/10 → 福岡、経済学部
一般入試 → 中期 → 12/11 → 福岡、経営学部


エラーチェックについて:
①試験会場についてのチェックと、学科についてのチェックは分けて行う
②エラーの場合はエラーメッセージをechoするのみ
③以下の配列($result)がPOSTで送信されてきます。ですので以下の$resultを使用し条件分岐をしたいです。

定義を色々書きましたが、要は以下の配列がPOST時に飛んでくるので、どうしても以下の値を使用しなければなりません。
*/

$result = array(

'course'=>array(
  '//EXAMG00001-0001/EN00000-101/EN10000-701/EN30000-001' => 'CRS000-001',
  '//EXAMG00001-0001/EN00000-101/EN10000-702/EN30000-001' => 'CRS000-001',
  '//EXAMG00001-0001/EN00000-102/EN10001-701/EN30000-001' => 'CRS000-002',
  '//EXAMG00001-0001/EN00000-102/EN10001-702/EN30000-002' => 'CRS000-002',
),

'place'=>array(
  '//EXAMG00001-0001/EN00000-101/EN10000-701/EN20000-101' => 'PLA000-001',
  '//EXAMG00001-0001/EN00000-101/EN10000-702/EN20000-102' => 'PLA000-002',
  '//EXAMG00001-0001/EN00000-102/EN10001-701/EN20000-103' => 'PLA000-003',
  '//EXAMG00001-0001/EN00000-102/EN10001-702/EN20000-103' => 'PLA000-003',
),

);

問題点

エラーチェックはコメントアウトに記述した通りです。

★エラーを表示させる条件

同一試験募集区分で複数受験する場合 ↓
例)前期 → 07/08 と 前期 → 07/09 を受験
例)中期 → 12/10 と 中期 → 12/11 を受験

①試験会場は両日程とも同じでなけらばならない。
②学科は両日程とも同じでなけらばならない。

今回の $result の場合だと
一般入試 → 前期 → 07/08 → 東京、経済学部
一般入試 → 前期 → 07/09 → 大阪、経済学部
一般入試 → 中期 → 12/10 → 福岡、経済学部
一般入試 → 中期 → 12/11 → 福岡、経営学部

前期で別試験会場が選択されている。
中期では別学科が選択されている。

という点でエラーを出さなければなりません。

惜しい部分まで行くのですが、中々成功しません。

どのように判定すれば良いでしょうか。

私は以下のようにしましたが、
「前期は両試験とも同一試験会場(学科)で中期は1試験のみ受験するが、前期とは異なる試験会場(学科)を選択する」
の場合にエラーになってくれません。

今回のように前期と中期共に2試験受験す場合はエラーになりますが、、、、。
良い方法を教えて下さい。お願いします。

自作コード

$courses = $result['course'];
$early_courses = [];
$middle_courses = [];
$places = $result['place'];
$early_places = [];
$middle_places = [];

//前期と中期の学科と試験会場
foreach ($courses as $course) {
    $early_courses[] = "EARLY_" . $course;
}
foreach ($courses as $course) {
    $middle_courses[] = "MIDDLE_" . $course;
}

foreach ($places as $place) {
    $early_places[] = "EARLY_" . $place;
}
foreach ($places as $place) {
    $middle_places[] = "MIDDLE_" . $place;
}


$exam_error_flag_course = false;
$exam_error_flag_place = false;
//選択された試験の数をカウントする。$result['place']でも同じ。
$exam_cnt = count($result['course']);
//選択された試験のキーを取得。$result['place']でも同じ。
$result_keys = array_keys($result['course']);
$early_section = "EN00000-101";
$early_section_cnt = 0;//前期の試験がいくつ選択されているかカウント
$middle_section = "EN00000-102";
$middle_section_cnt = 0;//中期の試験がいくつ選択されているかカウント

$early_course_economics = "EARLY_CRS000-001";
$early_course_economics_cnt = 0;
$early_course_management = "EARLY_CRS000-002";
$early_course_management_cnt = 0;

$middle_course_economics = "MIDDLE_CRS000-001";
$middle_course_economics_cnt = 0;
$middle_course_management = "MIDDLE_CRS000-002";
$middle_course_management_cnt = 0;


$early_place_tokyo = "EARLY_PLA000-001";
$early_place_tokyo_cnt = 0;
$early_place_osaka = "EARLY_PLA000-002";
$early_place_osaka_cnt = 0;
$early_place_fukuoka = "EARLY_PLA000-003";
$early_place_fukuoka_cnt = 0;

$middle_place_tokyo = "MIDDLE_PLA000-001";
$middle_place_tokyo_cnt = 0;
$middle_place_osaka = "MIDDLE_PLA000-002";
$middle_place_osaka_cnt = 0;
$middle_place_fukuoka = "MIDDLE_PLA000-003";
$middle_place_fukuoka_cnt = 0;


//前期と中期の試験が複数選択されているか確認する
for ($i = 0; $i < $exam_cnt; $i++) {
    if ($early_section == substr($result_keys[$i], 18, 11)) {
        $early_section_cnt++;
    }
    if ($middle_section == substr($result_keys[$i], 18, 11)) {
        $middle_section_cnt++;
    }
}


    /*

    同一試験募集区分で複数試験が選択されている場合、
    エラーが「出る」場合は以下である。

    選択されたそれぞれの試験会場と学科をカウントした場合、
    カウント数がもし1であればユーザー(受験者)は異なる試験会場や学科を選択肢している。

    */

    //前期の試験が複数選択されている場合
    //学科と試験会場をチェック
    if ($early_section_cnt >= 2) {
        foreach ($early_courses as $value) {
            if ($value == $early_course_economics) {
                $early_course_economics_cnt++;
            }
            if ($value == $early_course_management) {
                $early_course_management_cnt++;
            }

            if ($early_course_economics_cnt == 1 || $early_course_management_cnt == 1) {
                $exam_error_flag_course = true;
            }
        }

        foreach ($early_places as $value) {
            if ($value == $early_place_tokyo) {
                $early_place_tokyo_cnt++;
            }
            if ($value == $early_place_osaka) {
                $early_place_osaka_cnt++;
            }
            if ($value == $early_place_fukuoka) {
                $early_place_fukuoka_cnt++;
            }

            if ($early_place_tokyo_cnt == 1 || $early_place_osaka_cnt == 1 || $early_place_fukuoka_cnt == 1) {
                $exam_error_flag_place = true;
            }
        }
    }

    //中期の試験が複数選択されている場合
    //学科と試験会場をチェック
    if ($middle_section_cnt >= 2) {
        foreach ($middle_courses as $value) {
            if ($value == $middle_course_economics) {
                $middle_course_economics_cnt++;
            }
            if ($value == $middle_course_management) {
                $middle_course_management_cnt++;
            }

            if ($middle_course_economics_cnt == 1 || $middle_course_management_cnt == 1) {
                $exam_error_flag_course = true;
            }
        }

        foreach ($middle_places as $value) {
            if ($value == $middle_place_tokyo) {
                $middle_place_tokyo_cnt++;
            }
            if ($value == $middle_place_osaka) {
                $early_place_osaka_cnt++;
            }
            if ($value == $middle_place_fukuoka) {
                $middle_place_fukuoka_cnt++;
            }

            if ($middle_place_tokyo_cnt == 1 || $middle_place_osaka_cnt == 1 || $middle_place_fukuoka_cnt == 1) {
                $exam_error_flag_place = true;
            }
        }

    }

    if ($exam_error_flag_course) {
        echo "同一区分で複数の試験を受験する場合は別学科を受験できません";
        echo nl2br("\n");
    } else {
        echo "学科問題なし";
        echo nl2br("\n");
    }

    if ($exam_error_flag_place) {
        echo "同一区分で複数の試験を受験する場合は別試験会場で受験できません";
        echo nl2br("\n");
    } else {
        echo "試験会場問題なし";
    }
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 4

+5

せっかくの課題ですしフローチャートの作成をおすすめしたい
思い切って今作成中のコードを捨ててしまい、フローチャートが完成したらその通りにプログラムを書いてみましょう

惜しい部分まで行くのですが、中々成功しません。

この考え方をしている状態はプログラム作る上ではNGです
取ってつけての繰り返しの対応になって頭の中も書いたコードもゴッチャになる寸前か既になっていると思われます

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/14 06:16

    true or falseしかないですもんね。作り直した方がいいことも多いです。

    キャンセル

+3

前期と中期を通して学科や会場が同じでなければならない
という条件は提示されてないようですが?

まあ、結論からいうと、前期は前期だけ中期は中期だけを
チョイスしてるからそうなるわけでして、
通してチェックしたいなら前期や中期を分けずに
チェックすればいいはなしですな。

あと、変数名が長いのは初見で意味がとりやすくはありますが
コードを追っていく中ではなかなか負担になるわけでして、
機能を分けて(サブルーチン化して)短い変数名にすると
目がとどきやすくなると思います。
--- 追記 ---
現在のロジックをベースにするなら…
前期/中期の処理中に学科と会場を拾っておいて
最後に突き合わせるのが簡単だと思います。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+1

質問自体はつまみ食い程度にしか見てませんが、「条件判定が複雑」な場合の対処としては「判定部分を関数化して、名前を付け、可読性を高める」方法がメンテもしやすくなります。is_hoge() みたいな関数をつくり、判定部分を切り出して、if (is_hoge()) のように記述すると、読むのが楽でフローをおいやすくなります。

参考
真偽値を返す関数のネーミング

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

check解決した方法

-7

皆さまありがとうございます。

以下のコードででうまく行きました。

$result_keys = array_keys($result['course']);
//選択された試験の数をカウントする。$result['place']でも同じ。
$exam_amount = count($result['course']);

$early_section = "EN00000-101";
$early_section_cnt = 0;//前期の試験がいくつ選択されているかカウント
$middle_section = "EN00000-102";
$middle_section_cnt = 0;//中期の試験がいくつ選択されているかカウント

$course_economics = "CRS000-001";
$course_economics_cnt = 0;
$course_management = "CRS000-002";
$course_management_cnt = 0;


$place_tokyo = "PLA000-001";
$place_tokyo_cnt = 0;
$place_osaka = "PLA000-002";
$place_osaka_cnt = 0;
$place_fukuoka = "PLA000-003";
$place_fukuoka_cnt = 0;

$error_msg = "問題ありません";
$error_flag = false;

//学科と試験会場のキーを取得
$course_key_value = array_keys($result['course']);
$place_key_value = array_keys($result['place']);
//選択された学科と試験会場のコードを取得
foreach ($result['course'] as $value) {
    $courses[] = $value;
}
foreach ($result['place'] as $value) {
    $places[] = $value;
}

//キーとコードを結合する
for ($i = 0; $i < $exam_amount; $i ++) {
    $course_key_value[$i] .= '/' . $courses[$i];
}

for ($i = 0; $i < $exam_amount; $i ++) {
    $place_key_value[$i] .= '/' . $places[$i];
}

//前期と中期の試験が複数選択されているか確認する
foreach ($result_keys as $result_key) {
    //前期の試験が選択されているか
    if (strpos($result_key, $early_section) !== false) {
        $early_section_cnt ++;
    }

    if (strpos($result_key, $middle_section) !== false) {
        $middle_section_cnt ++;
    }
}

//前期の試験が複数選択されていれば
if ($early_section_cnt >= 2) {

  //前期の選択学科に問題がないか
    foreach ($course_key_value as $value) {
        if (strpos($value, $early_section) !== false && strpos($value, $course_economics) !== false) {
            $course_economics_cnt ++;
        }

        if (strpos($value, $early_section) !== false && strpos($value, $course_management) !== false) {
            $course_management_cnt ++;
        }
    }
    if ($course_economics_cnt == 1 || $course_management_cnt == 1) {
        $error_flag = true;
        $error_msg = '同一試験募集区分で複数の試験を受験する場合は同一学科しか選択できません。(前期)';
    }
    //別学科が選択されていれば
    if ($error_flag) {
        goto endOfValidationCheck;
    }
    //前期の試験会場に問題がないか
    foreach ($place_key_value as $value) {
        if (strpos($value, $early_section) !== false && strpos($value, $place_tokyo) !== false) {
            $place_tokyo_cnt ++;
        }

        if (strpos($value, $early_section) !== false && strpos($value, $place_osaka) !== false) {
            $place_osaka_cnt ++;
        }
        if (strpos($value, $early_section) !== false && strpos($value, $place_fukuoka) !== false) {
            $place_fukuoka_cnt ++;
        }
    }
    if ($place_tokyo_cnt == 1 || $place_osaka_cnt == 1 || $place_fukuoka == 1) {
        $error_flag = true;
        $error_msg = '同一試験募集区分で複数の試験を受験する場合は同一試験会場でしか選択できません。(前期)';
    }

    //学科と試験会場のカウント変数を初期化
    $course_management_cnt = 0;
    $course_economics_cnt = 0;
    $place_tokyo_cnt = 0;
    $place_osaka_cnt = 0;
    $place_fukuoka_cnt = 0;

    //別試験会場が選択されていれば
    if ($error_flag) {
        goto endOfValidationCheck;
    }
}


//中期の試験が複数選択されていれば
if ($middle_section_cnt >= 2) {

  //中期の選択学科に問題がないか
    foreach ($course_key_value as $value) {
        if (strpos($value, $middle_section) !== false && strpos($value, $course_economics) !== false) {
            $course_economics_cnt ++;
        }

        if (strpos($value, $middle_section) !== false && strpos($value, $course_management) !== false) {
            $course_management_cnt ++;
        }
    }
    if ($course_economics_cnt == 1 || $course_management_cnt == 1) {
        $error_flag = true;
        $error_msg = '同一試験募集区分で複数の試験を受験する場合は同一学科しか選択できません。(中期)';
    }
    //別学科が選択されていれば
    if ($error_flag) {
        goto endOfValidationCheck;
    }
    //中期の試験会場に問題がないか
    foreach ($place_key_value as $value) {
        if (strpos($value, $middle_section) !== false && strpos($value, $place_tokyo) !== false) {
            $place_tokyo_cnt ++;
        }

        if (strpos($value, $middle_section) !== false && strpos($value, $place_osaka) !== false) {
            $place_osaka_cnt ++;
        }
        if (strpos($value, $middle_section) !== false && strpos($value, $place_fukuoka) !== false) {
            $place_fukuoka_cnt ++;
        }
    }
    if ($place_tokyo_cnt == 1 || $place_osaka_cnt == 1 || $place_fukuoka == 1) {
        $error_flag = true;
        $error_msg = '同一試験募集区分で複数の試験を受験する場合は同一試験会場でしか選択できません。(中期)';
    }

    //学科と試験会場のカウント変数を初期化
    $course_management_cnt = 0;
    $course_economics_cnt = 0;
    $place_tokyo_cnt = 0;
    $place_osaka_cnt = 0;
    $place_fukuoka_cnt = 0;

    //別試験会場が選択されていれば
    if ($error_flag) {
        goto endOfValidationCheck;
    }
}

endOfValidationCheck:

echo $error_msg;

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/14 15:09

    他の回答者の回答を参考にすればできるのであえて私からそのままのコードを渡すことはしませんよ。
    現状、全部作り直さないとどうにもならないくらいのダメコードなので、それなりの対価が発生するレベルです。
    だから誰もコードで回答しないのです。

    キャンセル

  • 2019/07/14 15:27

    ありがとうございます。
    考え直します。

    キャンセル

  • 2019/07/14 15:45

    どのコードもほとんど読んではいないけど、各回答もらっておきながらgotoに行きつくとは
    紙一重で天才の素質があるかもしれないが、おとなしくgoto使わない頃までcomebackすべし

    キャンセル

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

  • ただいまの回答率 90.01%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる