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

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

ただいまの
回答率

88.09%

基本的には同じ処理だが、値の部分が微妙に違ってくる時 PHP

解決済

回答 2

投稿 編集

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

score 493

はじめに

同じような処理をしている時など、オブジェクト指向とかで簡潔にという事が言われたりもしていますが、、、

今やっている条件の分岐だったりも確かに同じ処理を何度か書く必要が出てきています。
しかし、これだったらこれ、あれだったらあれという部分においてその辺も含めてすっきり書けるものか、もう、このままズラズラ書くものか考えています。

アドバイス等いただければと思います。

基本的にやっていること

1.A,B,C,Dのいずれかを選択
2.WorkIn, WorkOut, RestIn, RestOutのいずれかを選択
3.送信
4.1,2の値が両方セットされてなければ何もしない、セットされれば次の処理
5.送信された時のYmd,Hiを取得
6.データベースで1の値とYmdを使ってSELECT
7.データが無ければInsert処理へ
8.データが有ったらUpdate処理へ
※このUpdate処理の部分で少し考えています。。。

データベース

tablename Test
id int not null primary key auto_increment,
Name varchar(2),
TimeDate date,
WorkIn time,
WorkOut time,
RestIn time,
RestOut time

Update部分

とりあえずInsertまでの部分に関しては共通の動きばかりなので、ここでは取り上げません。

// データベースにアクセスしてデータのチェック
$tableCheck = TableCheckDb($Name, $TimeDate);
if($tableCheck === false) {
  // データが無いので、WorkIn~RestOutまでどれを押されてもInsert処理させる
} else {
  // データがあったので、その値もチェックしていく必要がある
  // 1.そもそも上記②の値のどれが送られたかで条件分岐がはじまる
  if($value === "WorkIn") {

  } elseif($value === "WorkOut") {

  } elseif($value === "RestIn") {

  } elseif($value === "RestOut") {

  }
// 今回はこちらをテストとして記載していきます
if($value === "WorkIn") {
  // 選択されたのがWorkInだった時
  // データ自体は存在しているが、$tableCheck["WorkIn"]に値があるのかどうか?
  if($tableCheck["WorkIn"] !== "00:00:00") {
    // 既に入っている場合は今回では処理を終了とする
    return;
  } else {
    // データはあるが、WorkInにはまだ時刻が入っていない場合
    // データがあるので下記のような値がテーブルにあるとします
    /*
    * id 1
    * Name A
    * TimeDate '2017-02-07'
    * WorkIn '00:00:00'
    * WorkOut '00:00:00'
    * RestIn '00:00:00'
    * RestOut '00:00:00'
    */
    // 今回はUpdateなので、基本的な部分はテーブルからの値をそのまま使い、WorkInの部分だけ送信された時の時刻を入れることにします
       $this->id = $tableCheck["id"];
    $this->Name = $tableCheck["Name"];
    $this->WorkIn = $WorkIn // date('H:i')で取得した値
    $this->WorkOut = $tableCheck["WorkOut"];
    $this->RestIn = $tableCheck["RestIn"];
    $this->RestOut = $tableCheck["RestOut"];
    $this->_Update(// 値をセット);
}


Updateの部分自体は共通で良いと思うのですが、
今回の場合WorkInならWorkIn以外はテーブルのデータ、
WorkOutならWorkOut以外がテーブルのデータという事になろうかと思います。

それぞれを作ってもいいのですが、、、
function WorkIn_Upとかみたいに、、、
もし、すっきりこれで行けるかもという方法、又はそもそもこういうやり方自体が遠回りなやり方なんだとは思うのですが、、、アドバイス等いただければと思います。

今回は、これだけといえばこれだけですので、わざわざより書いた方が早いかもしれませんが、ここから項目の増化なりなんなりに応用できるかなと思ったので、、、

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+1

私だったら下記の様に書きますね。Ifを書くのは避けられそうになかったので、できるだけ集約しました。
少しは見通しが良くなると思います。

    public function update(){
        // データベースにアクセスしてデータのチェック
        $tableCheck = TableCheckDb($Name, $TimeDate);
        if($tableCheck === false) {
          // データが無いので、WorkIn~RestOutまでどれを押されてもInsert処理させる
        } else {
            // 既に入っている場合は今回では処理を終了とする
            if(!$this->checkValue($tablecheck, $value)){
                return;
            }
            // データがあったので、その値もチェックしていく必要がある
            // 1.そもそも上記②の値のどれが送られたかで条件分岐がはじまる
            $this->id = $tableCheck["id"];
            $this->Name = $tableCheck["Name"];
            $this->WorkIn = $tableCheck["WorkIn"]; // date('H:i')で取得した値
            $this->WorkOut = $tableCheck["WorkOut"];
            $this->RestIn = $tableCheck["RestIn"];
            $this->RestOut = $tableCheck["RestOut"];
            //ここで入ってきたパラメータによって、内容を上書きする
            //$infoには実際に設定したい$WorkIn等を入れておく想定
            $this->updateTableCheck($value,$Info);
        $this->_Update(// 値をセット);

        }   
    }

    /**
     * テーブルに値が入っていればfalseを返す
     * @param type $tablecheck
     * @param type $value
     * @return boolean
     */
    private function checkValue($tablecheck,$value){
        if($tableCheck[$value] !== "00:00:00"){
            return false;
        }
        return true;
    }

    /**
     * TableCheckを条件に応じてTableChekを上書きする。
     * @param type $tableCheck
     * @param type $value
     */
    private function updateTableCheck($value,$Info){
        //実際には$workinとかの情報を引数としてArrayに詰めて渡す。
        if($value === "WorkIn") {
            $this->WorkIn = $Array['WorkIn'];
        } elseif($value === "WorkOut") {
            $this->WorkOut = $Array['WorkOut'];
        } elseif($value === "RestIn") {
            $this->RestIn = $Array['RestIn'];
        } elseif($value === "RestOut") {
            $this->RestOut = $Array['RestOut'];
        }
    }

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/08 17:14

    回答感謝いたします!

    見通しがわかりやすくなり、こちらの回答を元に、現在実際にテストしているコードと置き換えつつ書いてみましたが、一つのメソッドのコード量も分散され、わかりやすくなりました!

    まだまだ、そもそもの設計部分などで荒さがあるかと思いますが、少しずつ綺麗に書けるようにしていきたいと思います。

    キャンセル

+1

こんにちは。
私でしたら、テーブル構造が示されたとおりであればおそらくズラズラ書くことにすると思います。

ここでは、別の方法をお示ししたいと思います。

1.テーブルは次のようにします。DB 不明なので、適宜合わせていただければと思います。

tablename Test
id int not null primary key auto_increment,
Name varchar(2),
TimeDate date,
TimeStamp time,
TimeKind char(1)

2.受信したときは、Insertだけを行います。TimeKind には、タイムスタンプの種別として、識別文字 WorkIn='a', WorkOut='b', RestIn='c', RestOut='d'(もっと増やせる...)などのように入れます。数値でも列挙型でもよいでしょう。

3.WorkIn, WorkOut, RestIn, RestOutデータを取り出すときに、次のようなSQL文を発行します。

SELECT
  Test.Name,
  Test.TimeDate,
  MIN(TestWorkIn.TimeStamp) WorkIn
  MAX(TestWorkOut.TimeStamp) WorkOut,
  MIN(TestRestIn.TimeStamp) RestIn,
  MAX(TestRestOut.TimeStamp) RestOut
 From Test
LEFT JOIN Test AS TestWorkIn ON TestWorkIn.Name=Test.Name AND TestWorkIn.TimeDate=Test.TimeDate AND TestWorkIn.TimeKind='a'
LEFT JOIN Test AS TestWorkOut ON TestWorkOut.Name=Test.Name AND TestWorkOut.TimeDate=Test.TimeDate AND TestWorkOut.TimeKind='b'
LEFT JOIN Test AS TestRestIn ON TestRestIn.Name=Test.Name AND TestRestIn.TimeDate=Test.TimeDate AND TestRestIn.TimeKind='c'
LEFT JOIN Test AS TestRestOut ON TestRestOut.Name=Test.Name AND TestRestOut.TimeDate=Test.TimeDate AND TestRestOut.TimeKind='d'
GROUP BY Test.Name, Test.TimeDate
ORDER BY Test.Name, Test.TimeDate

RestIn などの送信がない場合はNULLで返ります。NULL以外で返したい場合は、DBによりますがSQL文中にNVLやISNULLなどを使用して置き換えます。

同日・同一人物について同じ種類の送信がされた場合、WorkIn, RestInはいちばん最初の時刻(MINによる)、WorkOut, RestOutはいちばん遅い時刻(MAX)が採用されます。一旦WorkOutしたけど、追加の仕事をしてWorkingTimeが伸びた場合を考慮しています。2.のときに同一条件の送信が登録されていたら、種別に応じて無視するか、古いレコードを削除して追加するかUpdateするようにすれば、GROUP BY などの集合演算が不要になり、レコード数も無駄がなくなります。ただ、タイムカード関連の運用は利用者のトラブル(他人のを間違えて押してしまった、カードがうまく認識されなかったなど)がつきものであり、ログ的にデータを記録をしておくと便利なので、私はひたすらInsertさせるように作ります。

ご参考になれば幸いです。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/02/08 17:10

    回答大変感謝いたします。

    私では、はっきり言ってまだこちら側から考えていくというのを全く思いつきませんでした。。。
    そして、Insertの後はUpdateだろうという固まった考えでありましたが、Insertだけさせることで、ログとしての機能も持たせていくという事で、とても参考になりました!

    試してみたいと思います!

    キャンセル

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

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

関連した質問

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