728x90

약관동의 체크박스는 보기에는 간단한데 의외로 체크해야할 로직이 많다. 전체 동의를 하면 하위 체크박스가 모두 선택 되어야 하고 하나가 풀리면 전체동의 체크박스도 풀려야 하고 필수 동의 체크값에 따라 하위 버튼도 disabled 가 해제 되어야 해서 체크박스가 선택 될때마다 하단 등록 버튼 상태를 변경하는 로직은 한번 정리해두는게 좋다. 

 

아래 예시는 하단에 확인 버튼의 disabled 속성을 isConfirmDisabled 변수에 담고 체크박스의 값에 따라 watch 에서 체크 하는 로직으로 구현 하였다. 체크박스 상태가 변경 될때마다 확인이 되어야 하는 부분이어서 watch 로 걸어 주는것이 조금 더 편리하다. vue 에서 watch 는 너무 많이 걸면 조건이 꼬이기도 하니까 주의할 필요가 있다.  

<template>
  <CheckField
    v-for="(term, index) in terms"
    :key="index"
    v-model="term.agreed"
    :class="'terms-item'"
    :label="term.text"
    :required-indicator="term.required"
    :optional-indicator="!term.required"
    :show-view-button="index !== 0"
    :toggle-checkbox="index === 3 ? toggleMarketingConsent : () => {}"
    @view="() => clickConsent(term.content, index)"
  />
  <button :disabled="isConfirmDisabled">확인</button>
</template>

<script setup>
import { ref, watch } from 'vue';

const terms = ref([
  { agreed: false, text: '항목 1', required: true, content: '내용 1' },
  { agreed: false, text: '항목 2', required: true, content: '내용 2' },
  { agreed: false, text: '항목 3', required: false, content: '내용 3' },
  { agreed: false, text: '마케팅 동의', required: false, content: '내용 4' },
]);

const isConfirmDisabled = ref(true);

// 모든 항목의 동의 상태를 체크
watch(
  () => terms.value.map(term => term.agreed),
  (newAgreements) => {
    const allAgreed = terms.value[0]?.agreed && 
                      terms.value[1]?.agreed && 
                      terms.value[2]?.agreed;

    isConfirmDisabled.value = !allAgreed; // 모두 동의하지 않으면 버튼 비활성화
  },
  { immediate: true } // 컴포넌트 마운트 시 즉시 체크
);
</script>
728x90
728x90

쿼리문에서 되도록 group by 를 안쓰는 구조로 테이블구조를 잡는것이 좋지만 의외로 group by 를 해야 하는 경우가 꽤 많이 발생한다. 이때 그룹핑을 했을때 페이징 관련 처리 방법을 php 코드를 예시로 아래와 같이 정리해 본다. 

 

 

group by 예시 쿼리문

SELECT column1, COUNT(*)
FROM your_table
GROUP BY column1
ORDER BY COUNT(*) DESC
LIMIT 10;

 

group by 로 php 코드에서 페이징 처리 예시

<?php
// 데이터베이스 연결 설정
$host = 'localhost';
$dbname = 'your_database';
$username = 'your_username';
$password = 'your_password';

try {
    $pdo = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
    echo "Connection failed: " . $e->getMessage();
}

// 페이지 번호와 페이지당 항목 수 설정
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1; // 현재 페이지
$limit = 10; // 페이지당 항목 수
$offset = ($page - 1) * $limit; // OFFSET 계산

// 총 게시물 수를 가져오기
$totalQuery = $pdo->query("SELECT COUNT(*) FROM board");
$totalRows = $totalQuery->fetchColumn();
$totalPages = ceil($totalRows / $limit); // 총 페이지 수

// 데이터 가져오기
$query = $pdo->prepare("SELECT * FROM board ORDER BY created_at DESC LIMIT :offset, :limit");
$query->bindParam(':offset', $offset, PDO::PARAM_INT);
$query->bindParam(':limit', $limit, PDO::PARAM_INT);
$query->execute();
$posts = $query->fetchAll(PDO::FETCH_ASSOC);

// 결과 출력
foreach ($posts as $post) {
    echo "<h2>" . htmlspecialchars($post['title']) . "</h2>";
    echo "<p>" . htmlspecialchars($post['content']) . "</p>";
}

// 페이지 네비게이션
echo '<div class="pagination">';
if ($page > 1) {
    echo '<a href="?page=' . ($page - 1) . '">이전</a>';
}

for ($i = 1; $i <= $totalPages; $i++) {
    if ($i == $page) {
        echo '<strong>' . $i . '</strong>'; // 현재 페이지 표시
    } else {
        echo '<a href="?page=' . $i . '">' . $i . '</a>';
    }
}

if ($page < $totalPages) {
    echo '<a href="?page=' . ($page + 1) . '">다음</a>';
}
echo '</div>';
?>
728x90
728x90

쿼리문을 작성하다보면 특이한 경우의 수가 많이 생긴다. 보통은 제품명을 하나로 입력하지만 고객사에서 자동으로 입력되길 원해서 필터값을 모두 조합해서 등록해야 하는 경우도 생긴다. 그런데 이때 필터값은 보통 코드 테이블에 공통으로 관리 하는데 그러면 테이블 join 을 해서 subquery 로 가져 와야 하는데 이런 단어들은 어떻게 합쳐야 할찌 난감할때가 있다. 

 

등록이 안된 필터는 null 이나 공백을 내 놓을테니 그 부분도 대응을 해야 한다. 아래 예시는 필터 정보를 | 기호로 하나로 합쳐서 select 해주는 쿼리문이다. CONCAT 는 문자열을 합치는 용도로 쓰는데 의외로 많이 쓰이기 때문에 알아 두는것이 유용하다. 

$sql = "SELECT 
      CONCAT(
        COALESCE((SELECT name FROM material_category WHERE id = G.goods_cate), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_1), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_2), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_3), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_4), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_5), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_6), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_7), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_8), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_9), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_10), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_11), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_12), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_13), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_14), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_15), ''), '|', 
        COALESCE((SELECT name FROM material_category WHERE id = G.filter_16), '')
      ) AS full_name
    FROM goods G
    WHERE goods_idx = :goods_idx";

$stmt = $this->pdo->prepare($sql);
$stmt->bindValue(':goods_idx', $goods_idx, \PDO::PARAM_INT);
$stmt->execute();

// fetch()로 결과를 가져오고, full_name만 반환
$result = $stmt->fetch(\PDO::FETCH_ASSOC);
return $result['full_name'] ?? null; // full_name이 없을 경우 null 반환

 

이렇게 합쳐진 full_name 만 return 해주는 함수 예시로 pdo 로 DB 연동을 하고 있다면 참조 하면 좋을거 같다.  

728x90

+ Recent posts