CI 묻고 답하기

제목 쿼리 성공여부를 검증하는 로직 적용되었을 때, 작동이 되지 않습니다.
카테고리 CI 2, 3
글쓴이 Chris Ray 작성시각 2018/02/22 08:44:43
댓글 : 8 추천 : 0 스크랩 : 0 조회수 : 17131   RSS

컨트롤러 코드

 

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Register extends CI_Controller {

	/**
	 * Index Page for this controller.
	 *
	 * Maps to the following URL
	 * 		http://example.com/index.php/welcome
	 *	- or -
	 * 		http://example.com/index.php/welcome/index
	 *	- or -
	 * Since this controller is set as the default controller in
	 * config/routes.php, it's displayed at http://example.com/
	 *
	 * So any other public methods not prefixed with an underscore will
	 * map to /index.php/welcome/<method_name>
	 * @see https://codeigniter.com/user_guide/general/urls.html
	 */

    // private $validationStatus = null;

    public function __construct() {
        parent::__construct();

        $this->load->helper(['url', 'date']);
        $this->load->library('form_validation');
        $this->load->model('register/user_model', 'UserRegister');
    }

    private function _procAssets() {
        $procAssets = [
            'style_css' => base_url('assets/css/style.css'),
            'fontawesome_css' => base_url('assets/css/fontawesome-all.min.css'),
            'your_ip' => $this->input->server('REMOTE_ADDR'),
            'assets_ver' => mdate('%Y%m%d' ,now())
        ];

        return $procAssets;
    }

    private function _procJoinValidation() {
        // $joinData = $this->_getJoinData();
        // CI 폼검증 라이브러리를 활용한 검증 메서드

        $joinRules = [
            [
                'field' => 'mn-userId',
                'label' => 'mn-userId',
                'rules' => 'required|min_length[5]|max_length[20]'
            ],
            [
                'field' => 'mn-userPw',
                'label' => 'mn-userPw',
                'rules' => 'required|min_length[10]|max_length[20]'
            ],
            [
                'field' => 'mn-userPwConfirm',
                'label' => 'mn-userPwConfirm',
                'rules' => 'required|matches[mn-userPw]'
            ],
            [
                'field' => 'mn-userPhone',
                'label' => 'mn-userPhone',
                'rules' => 'required|min_length[9]|max_length[11]'
            ],
            [
                'field' => 'mn-userCountry',
                'label' => 'mn-userCountry',
                'rules' => 'required'
            ]
        ];

        $this->form_validation->set_rules($joinRules);
        // 폼 검증 규칙을 배열에 담고 set_rules() 메서드의 인자로 전달하는 방법이다.
        // $this->validationStatus = $this->form_validation->run();
        // $this->validationStatus = is_bool($this->validationStatus);

        // return $this->validationStatus;
        return $this->form_validation->run();
    }

    private function _setJoinData() {
        $joinData = $this->input->post();

        // $joinData['userId'] = $this->input->post('mn-userId');
        // $joinData['userPw'] = $this->input->post('mn-userPw');
        // $joinData['userPwc'] = $this->input->post('mn-userPwConfirm');
        // $joinData['userPhone'] = $this->input->post('mn-userPhone');
        // $joinData['userCountry'] = $this->input->post('mn-userCountry');

        // $this->input->post(); 에서 인자가 없을 경우 모든 post를 배열로 리턴되므로,
        // $data = $this->input->post(); 면,
        // $data['mn-userId'] 와 같이 연관배열의 키로써 접근할 수 있다.

        return $joinData;
    }

    private function _getJoinData() {
        return $this->_setJoinData();
    }

    private function _procJoin() {
        $joinData = $this->_getJoinData();

        $this->UserRegister->joinUser($joinData);
    }

    // private function _joinRedirect() {
    //     // $this->_procJoin();

    //     // if($this->UserRegister->_getStatus()) {
    //     //     redirect(base_url('index.php/register'));
    //     // } else {
    //     //     redirect(base_url());
    //     // }
    //     if($this->_procJoinValidation()) {
    //         if($this->UserRegister->_getStatus()) {
    //             redirect(base_url('index.php/register'));
    //         } else {
    //             redirect(base_url());
    //         }
    //     } else {
    //         echo '폼 검증 에러';
    //     }
    // }

	public function index()
	{
        $this->load->view('register', $this->_procAssets());

        // echo $this->validationStatus;
        
        if($this->input->method() == 'post' && $this->_procJoinValidation() == TRUE && $this->UserRegister->_getStatus() == TRUE) {
            $this->_procJoin();
            // if($this->UserRegister->_getStatus()) {
            //     $this->_procJoin();
            // }
            // $this->_joinRedirect();
        }
	}
}

 

모델 코드

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class User_model extends CI_Model {
    private $_resultStatus = null;
    private $_encryptKey = 'saltKey';

    public function __construct() {
        parent::__construct();

        $this->load->database();
    }

    private function _procEncrypt($data) {
        $enc = md5($data.$this->_encryptKey);
        
        return $enc;
    }

    private function _setStatus($resultStatus) {
        return $this->_resultStatus = $resultStatus;
    }

    public function _getStatus() {
        return $this->_resultStatus;
    }

    public function joinUser($data) {
        $joinData = [
            'id' => $data['mn-userId'],
            'password' => $this->_procEncrypt($data['mn-userPw']),
            'phone' => $data['mn-userPhone'],
            'email' => null,
            //'last_at' => 'NOW()',
            'ip' => ip2long($this->input->server('REMOTE_ADDR')),
            'nationality' => $data['mn-userCountry']
        ];

        $this->db->set('last_at', 'now()', false);
        // set(필드, now(), false);
        // set() 메서드로 MySQL 의 NOW()로 인식시키는 방법
        // TIMESTAMP 가 0000-00-00 00:00:00 으로 들어가는 걸 해결할 수 있다.
        $resultStatus = $this->db->insert('accounts', $joinData);
        // insert() 메서드는 insert query를 생성하고 바로 실행한다.
        // 그 후 $resultStatus 에 담는데,
        $resultStatus = is_bool($resultStatus);
        // PHP Native is_bool() 로 boolean 형으로 $resultStatus에 저장한다.

        $this->_setStatus($resultStatus);
        // _setStatus() setter 메서드로 boolean type 데이터를 보내주고, 이것을 field $resultStatus에 저장한다.
        // 마지막으로, 컨트롤러에서 접근할 수 있게 public _getStatus() getter 메서드를 이용해 보내준다.
    }
}

 

문제는 컨트롤러 index() 의 

if($this->input->method() == 'post' && $this->_procJoinValidation() == TRUE && $this->UserRegister->_getStatus() == TRUE) {
     $this->_procJoin();
}

에서 발생하는데index() if 의

$this->UserRegister->_getStatus() == TRUE

에서 문제인 걸로 확인이 되었습니다.

 

$this->UserRegister->_getStatus() 는 insert가 제대로 되었는지의 여부를 $_resultStatus 필드를 통해 boolean 으로 리턴해주고자 했고,이걸 이용해서 쿼리가 성공일 경우에만 이라는 검증만 넣으면 문제가 발생합니다.

 

어떻게 해야 좋을까요?

더불어, 질문글을 보기 좋게 작성했는지와 CI를 잘 활용하고 있는지 평가도 부탁드립니다.

CI 는 2일차, PHP 2주차 초보가 질문 올립니다. 감사합니다.

 다음글 하나도 안건드렸는데, welcome 페이지가 404에러... (12)
 이전글 controller 백그라운드 진행 (2)

댓글

변종원(웅파) / 2018/02/22 09:25:03 / 추천 0

insert는 insert_id()로, update, delete는 affected_rows()로 검증하시면 됩니다. 매뉴얼 참고하세요

그리고 boolean 비교는 === 로 하시는게 좋습니다.

Chris Ray / 2018/02/22 09:34:27 / 추천 0

@변종원(웅파) 답변 감사합니다. AR에 대해서는 말씀주신 메서드를 메뉴얼에서 참고해보겠습니다.

지적해주신 boolean 비교에 대해서 말인데,

1. $is == TRUE

2. $is === TRUE 

1번은 값 비교에 가깝고(스트링 TRUE 일수도 있으므로), 2번은 비교하되, 객체까지 일치한지를 좀 더 엄격한 확인을 한다고 이해해도 되는건가요?

kaido / 2018/02/22 09:40:47 / 추천 0

특별한 이유가 없다면 getter setter 설정 안하셔도 됩니다.

프레임워크안에서 자동으로 맵핑을 제공하지 않는이상 습관적인 겟터셋터는 지양해야 하는것이 맞습니다 ^^

자바진영도 불필요한 겟터셋터는 줄여야 한다고 말이 나오고 있구요.

is_boolean() 하지 않아도 true , false 으로 제공 합니다.

echo 상에는 0,1 로 찍히지만 이는 php auto casting 에 의한것입니다.

(int) 0 , false , null , (string) 0

if 비교문에서는 전부 동일하게 처리됩니다.

또한 문자 0 이라도 숫자와 비교문이 들어가면 php는 에러를 뱉지 않고 문자 0을 숫자 0으로 바꿔서 비교합니다.

null , false가 대상이면 null, false으로 바꿔서 비교하구요.

mysql db 필드가 숫자 형태일때 문자 0 을 넣으면 숫자 0 으로 자동으로 바뀌어서 들어갑니다.

어느 언어에도 없는 php 만의 특수한 형변환 입니다.

그래서 타입 선언에 대해서 크게 골머리 썩지 않아도 됩니다 ㅎㅎㅎ

 

그래서 boolean 비교에는 ===  이렇게 비교하셔야합니다.

[좀더 정확하게는 숫자만 인지, 문자만인지, 빈값인지, 공백인지 비교하는 함수들이 전부 있습니다.]

 

단순하게 비교하실거면 모델에서 바로 return 해버리면 성공 실패여부를 간단히 알수 있고, 좀더 세밀하게 컨트롤 하실거면 웅파님 조언대로 affected_rows() 이라는 함수가 ci 에서 제공하고 있습니다.

Chris Ray / 2018/02/22 09:51:55 / 추천 0
@kaido 님 답변 감사합니다. 제 코드 수준이 낮은 것 같아서 올리기가 망설여졌었는데, 실력자분들께서 친절히 답변해주시니 감사할 뿐입니다.
이제다시 / 2018/02/22 10:01:14 / 추천 0

$this->UserRegister->_getStatus() == TRUE

위 상태값을 받아오는 부분은 $this->UserRegister->joinUser($joinData); 여기에서 셋팅하는데

먼저 받아오면 초기값인 null 을 받아올 수 밖에 없어 보입니다. 

 

그리고 is_bool() 함수는 변수값이 boolean 타입인지 아닌지를 판단하는 함수인데

실행한다면 true 든 false 든 true 를 반환합니다. 

 

또 $this->db->insert 문은 true/ false 를 반환하는데 바로 return 해서 비교하는게 좋을거 같습니다. 

 

index 페이지를 뷰페이지와 처리페이지로 동시에 사용할려는 의도 같은데 

시작부분에 뷰파일을 렌더하고 처리하지말고 validate 를 통과할 경우 처리 / 실패일 경우 뷰렌더링

 

전체적으로 코드를 너무 쪼개놓은 느낌인데 공통파일은 config 를 이용하고, 불필요한 메소드를 줄이고

코드 진행 순서만 잘 생각한다면 좋을거 같습니다. 

Chris Ray / 2018/02/22 10:19:31 / 추천 0

@이제다시 님 답변 감사드립니다.

if($this->input->method() == 'post' && $this->_procJoinValidation() === TRUE && $this->_procJoin() === TRUE) {
redirect(base_url('index.php/register'));
}

위와 같이 수정하면 흐름이 의도대로 됩니다. 정확히 좋은 방법인지는 모르겠네요

Chris Ray / 2018/02/22 10:42:05 / 추천 0
    public function index()
    {
$this->load->view('register', $this->_procAssets());
 
if($this->input->method() == 'post' && $this->_procJoinValidation() === TRUE && $this->_procJoin() === TRUE) {
redirect(base_url());
}
    }

방금 발견한 문제점입니다. 검증 3개 거치고, redirect() 가 먹히질 않네요

변종원(웅파) / 2018/02/22 11:36:56 / 추천 0

로직도 좀 이상합니다. 

뷰를 먼저 출력하고 post 전송이 있고 입력이 성공하면 다른 주소로 리다이렉트..

보통은 

if(포스트 전송이 있는지)

{

  //있다면 입력 처리후 리다이렉트

}

else

{

  //없으면 뷰 출력 

}

이렇게 처리합니다.

뷰와 post 처리 메소드를 분리하는 방식도 있구요.