검색 화면에서 분류를 안 고르면 목록이 비어 나온다는 문의가 있었다. 화면을 열어 보니 분류 select 가 빈칸으로 시작한다.
Table of contents
Open Table of contents
안 고른 상태에 이름이 없었다
선택 상자를 그리는 코드다.
<select name="category">
<?php foreach ($categories as $c): ?>
<option value="<?= $c->category_no ?>"><?= $c->name ?></option>
<?php endforeach; ?>
</select>
첫 항목이 바로 분류다. selected 가 안 붙어 있으면 첫 option 이 저절로 골라진 것이 된다고 규격에 적혀 있다.
그런데 이 화면에서는 jQuery 로 초기값을 비워 두고 있어서 아무것도 안 보인다. 안 골랐다는 상태에 항목이 없으니 빈칸이 된다.
사용자는 그 빈칸을 보고 무엇을 해야 하는지 모른다. 상태를 담는 자리는 있는데 그 자리에 이름이 없었다.
안내 항목을 넣었다
<select name="category">
<option value="">분류를 선택하세요</option>
<?php foreach ($categories as $c): ?>
<option value="<?= $c->category_no ?>"><?= $c->name ?></option>
<?php endforeach; ?>
</select>
값이 빈 문자열인 option 을 맨 앞에 뒀다. 안 고른 상태가 화면에 보이고 사용자가 그 문구를 보고 판단할 수 있다.
서버 쪽 처리도 봤다
빈 값이 넘어오면 서버가 어떻게 처리하는지 확인했다.
$category = $this->input->get('category');
$this->db->where('category_no', $category);
빈 문자열로 조회하니 category_no = '' 인 상품이 없어서 0건이다. 이것이 빈 목록의 원인이었다.
$category = $this->input->get('category');
if ($category !== '' && $category !== null) {
$this->db->where('category_no', (int)$category);
}
안 골랐으면 조건을 안 걸고 전체가 나온다. 화면만 고치면 문구만 바뀌고 결과는 그대로다.
판정을 empty() 로 두지는 않았다. PHP 에서 empty() 는 문자열 '0' 도 참으로 보기 때문에 분류 번호가 0인 것이 생기면 안 고른 것과 구분이 안 된다.
전체와 안 고름의 구분
여기서 하나 더 나왔다. 사용자가 전체를 보고 싶다는 것과 아직 안 골랐다는 것은 다른 의도다.
검색 화면에서는 둘이 같아도 되고 안 고르면 전체다. 그런데 등록 화면은 category_no 를 반드시 골라야 하고 안 고른 채로 저장되면 안 된다.
검색 화면 "전체"
등록 화면 "분류를 선택하세요" + 필수 검사
화면 성격에 따라 안내 문구를 다르게 했다.
등록 화면에서 화면 쪽 검사만 있었던 것도 고쳤다.
if (!$('#category').val()) {
alert('분류를 선택하세요');
return false;
}
주소로 직접 요청하면 이 alert 검사를 안 거치므로 input->post 를 보는 검사를 서버에도 넣었다.
if (!$this->input->post('category')) {
return $this->fail('분류는 필수입니다');
}
화면 검사는 편의고 서버 검사가 방어다.
검증 — 기존 자료와 다른 선택 상자
검사를 넣기 전에 저장된 것 중 분류가 빈 것이 있는지 봤다.
SELECT COUNT(*) FROM product WHERE category_no IS NULL OR category_no = 0;
-- 63
63건이었다. 화면 검사만 있던 기간에 다른 경로로 들어온 것들이라 목록을 뽑아 담당자에게 넘기고 채워진 뒤에 NOT NULL 제약을 걸었다.
같은 상태인 곳이 더 있는지도 찾았다.
$ grep -rn "<select" --include=*.php application/views/ | wc -l
41
select 가 41개였고 각각 첫 항목이 안내인지 봤다. 안내 항목이 있는 것이 22개이고 없는 것이 19개였다.
19개 중 12개는 값이 반드시 있어야 하는 것이라 안내 항목을 넣었고 나머지 7개는 첫 항목이 기본값으로 맞는 것이어서 그대로 뒀다. 전부 넣는 것이 아니라 첫 항목이 기본값으로 맞는지를 본다.
문의에 정렬이 이상하다는 것도 있었는데 order_by 가 category_no 순이라 사람이 보기에 순서가 없었다.
ALTER TABLE category ADD COLUMN sort_no INT NOT NULL DEFAULT 0;
$this->db->order_by('sort_no', 'ASC')->order_by('name', 'ASC');
sort_no 가 같으면 이름 순이다. 두 번째 정렬이 없으면 같은 값끼리 순서가 매번 달라진다.
정리
- 선택하지 않은 상태에 항목이 없으면 빈칸이 보인다
selected가 없으면 첫option이 골라진 것이 된다- 값이 빈 안내 항목을 맨 앞에 두고 문구를 넣는다
- 빈 값이 서버로 갔을 때 조건을 안 걸게 한다
- 화면만 고치면 문구만 바뀌고 결과는 그대로다
- 빈 값 판정을
empty()로 하면'0'이 함께 걸린다 - 전체를 뜻하는 것과 안 골랐다는 것을 구분해 문구를 나눈다
- 화면 검사는 편의고 서버 검사가 방어다
- 검사를 넣기 전에 이미 들어간 자료를 확인한다
- 선택 상자를 전수로 훑되 첫 항목이 기본값으로 맞는지를 기준으로 본다
- 정렬 컬럼이 같은 값이면 두 번째 정렬을 준다