위젯 없이 데이터 조회하기¶
위젯을 사용하지 않고 직접 데이터베이스에서 데이터를 조회하여 레이아웃에 표시하는 방법을 설명합니다.
📋 기본 개념¶
위젯을 사용하지 않고 직접 데이터를 조회하는 방법은 다음과 같은 장점이 있습니다:
- 성능 향상 (위젯 오버헤드 제거)
- 커스터마이징 자유도 증가
- 캐싱 전략의 직접 제어
🔧 기본 사용법¶
1. Context 객체를 통한 데이터 조회¶
<!-- 레이아웃 파일에서 -->
{@
$args = new stdClass();
$args->module_srl = 123; // 게시판 모듈 번호
$args->list_count = 5; // 가져올 글 수
$args->page = 1;
$oDocumentModel = getModel('document');
$output = $oDocumentModel->getDocumentList($args);
$document_list = $output->data;
}
<!-- 데이터 출력 -->
<div class="recent-posts">
<h3>최근 게시물</h3>
<ul>
<!--@foreach($document_list as $document)-->
<li>
<a href="{getUrl('','mid',$document->get('mid'),'document_srl',$document->get('document_srl'))}">
{$document->get('title')}
</a>
<span class="date">{zdate($document->get('regdate'), 'Y-m-d')}</span>
</li>
<!--@end-->
</ul>
</div>
2. 직접 DB 쿼리 사용¶
{@
// executeQuery를 사용한 직접 쿼리
$args = new stdClass();
$args->module_srl = 123;
$args->list_count = 10;
$output = executeQuery('layout.getRecentDocuments', $args);
$recent_docs = $output->data;
}
<div class="custom-recent-list">
<!--@foreach($recent_docs as $doc)-->
<div class="post-item">
<h4><a href="{getUrl('','mid',$doc->mid,'document_srl',$doc->document_srl)}">{$doc->title}</a></h4>
<p class="meta">
<span class="author">{$doc->nick_name}</span>
<span class="date">{zdate($doc->regdate, 'Y.m.d')}</span>
<span class="comments">댓글 {$doc->comment_count}</span>
</p>
</div>
<!--@end-->
</div>
📊 실전 예제¶
1. 게시판별 최신 글 탭형 출력¶
{@
// 여러 게시판의 최신 글을 한번에 조회
$board_list = array(
array('srl' => 123, 'name' => '공지사항', 'mid' => 'notice'),
array('srl' => 124, 'name' => '자유게시판', 'mid' => 'free'),
array('srl' => 125, 'name' => 'FAQ', 'mid' => 'faq')
);
$tab_data = array();
foreach($board_list as $board) {
$args = new stdClass();
$args->module_srl = $board['srl'];
$args->list_count = 5;
$args->order_type = 'regdate';
$oDocumentModel = getModel('document');
$output = $oDocumentModel->getDocumentList($args);
$tab_data[$board['mid']] = array(
'name' => $board['name'],
'list' => $output->data
);
}
}
<div class="tab-recent-posts">
<ul class="tab-nav">
<!--@foreach($tab_data as $mid => $data)-->
<li><a href="#tab-{$mid}" onclick="showTab('{$mid}')">{$data.name}</a></li>
<!--@end-->
</ul>
<!--@foreach($tab_data as $mid => $data)-->
<div id="tab-{$mid}" class="tab-content">
<ul>
<!--@foreach($data.list as $doc)-->
<li>
<a href="{getUrl('','mid',$mid,'document_srl',$doc->document_srl)}">
{cut_str($doc->title, 30, '...')}
</a>
<span class="date">{zdate($doc->regdate, 'm.d')}</span>
</li>
<!--@end-->
</ul>
</div>
<!--@end-->
</div>
<script>
function showTab(mid) {
// 모든 탭 숨기기
var tabs = document.querySelectorAll('.tab-content');
tabs.forEach(function(tab) {
tab.style.display = 'none';
});
// 선택된 탭 보이기
document.getElementById('tab-' + mid).style.display = 'block';
}
// 첫 번째 탭 기본 활성화
document.addEventListener('DOMContentLoaded', function() {
var firstTab = document.querySelector('.tab-content');
if(firstTab) firstTab.style.display = 'block';
});
</script>
2. 인기글과 최신 댓글 동시 출력¶
{@
// 인기글 조회 (조회수 기준)
$args_popular = new stdClass();
$args_popular->module_srl = 123;
$args_popular->list_count = 5;
$args_popular->order_type = 'readed_count';
$args_popular->period = 7; // 7일간
$oDocumentModel = getModel('document');
$popular_output = $oDocumentModel->getDocumentList($args_popular);
$popular_list = $popular_output->data;
// 최신 댓글 조회
$args_comment = new stdClass();
$args_comment->module_srl = 123;
$args_comment->list_count = 5;
$oCommentModel = getModel('comment');
$comment_output = $oCommentModel->getNewestCommentList($args_comment);
$comment_list = $comment_output->data;
}
<div class="sidebar-widgets">
<!-- 인기글 -->
<div class="widget popular-posts">
<h3>이번 주 인기글</h3>
<ul>
<!--@foreach($popular_list as $doc)-->
<li>
<a href="{getUrl('','mid',$doc->get('mid'),'document_srl',$doc->get('document_srl'))}">
{cut_str($doc->get('title'), 25, '...')}
</a>
<span class="meta">
<span class="views">조회 {number_format($doc->get('readed_count'))}</span>
<span class="comments">댓글 {$doc->get('comment_count')}</span>
</span>
</li>
<!--@end-->
</ul>
</div>
<!-- 최신 댓글 -->
<div class="widget recent-comments">
<h3>최신 댓글</h3>
<ul>
<!--@foreach($comment_list as $comment)-->
<li>
<div class="comment-author">{$comment->getNickName()}</div>
<div class="comment-content">
<a href="{getUrl('','mid',$comment->get('mid'),'document_srl',$comment->get('document_srl'))}#comment_{$comment->get('comment_srl')}">
{cut_str(strip_tags($comment->get('content')), 40, '...')}
</a>
</div>
<div class="comment-date">{zdate($comment->get('regdate'), 'Y.m.d H:i')}</div>
</li>
<!--@end-->
</ul>
</div>
</div>
3. 갤러리형 이미지 게시물¶
{@
// 이미지가 있는 게시물만 조회
$args = new stdClass();
$args->module_srl = 126; // 갤러리 게시판
$args->list_count = 8;
$args->order_type = 'regdate';
$output = executeQuery('layout.getDocumentsWithImages', $args);
$gallery_list = $output->data;
}
<div class="gallery-widget">
<h3>최신 갤러리</h3>
<div class="gallery-grid">
<!--@foreach($gallery_list as $item)-->
<div class="gallery-item">
<a href="{getUrl('','mid',$item->mid,'document_srl',$item->document_srl)}">
<!--@if($item->thumbnail)-->
<img src="{$item->thumbnail}" alt="{$item->title}" loading="lazy">
<!--@else-->
<img src="/common/img/no-image.png" alt="이미지 없음">
<!--@end-->
<div class="overlay">
<h4>{cut_str($item->title, 20, '...')}</h4>
<p>{zdate($item->regdate, 'Y.m.d')}</p>
</div>
</a>
</div>
<!--@end-->
</div>
</div>
<style>
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 10px;
}
.gallery-item {
position: relative;
overflow: hidden;
border-radius: 8px;
}
.gallery-item img {
width: 100%;
height: 120px;
object-fit: cover;
transition: transform 0.3s ease;
}
.gallery-item:hover img {
transform: scale(1.1);
}
.overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(transparent, rgba(0,0,0,0.8));
color: white;
padding: 10px;
transform: translateY(100%);
transition: transform 0.3s ease;
}
.gallery-item:hover .overlay {
transform: translateY(0);
}
</style>
📈 성능 최적화¶
1. 캐싱 활용¶
{@
$cache_key = 'recent_posts_' . $module_srl;
$cache_time = 300; // 5분
$cached_data = FileHandler::readFile('./files/cache/layout/' . $cache_key . '.cache');
if($cached_data && (time() - filemtime('./files/cache/layout/' . $cache_key . '.cache')) < $cache_time) {
$recent_list = unserialize($cached_data);
} else {
// 데이터 조회
$args = new stdClass();
$args->module_srl = $module_srl;
$args->list_count = 10;
$oDocumentModel = getModel('document');
$output = $oDocumentModel->getDocumentList($args);
$recent_list = $output->data;
// 캐시 저장
FileHandler::writeFile('./files/cache/layout/' . $cache_key . '.cache', serialize($recent_list));
}
}
2. 조건부 로딩¶
{@
// 특정 페이지에서만 데이터 로드
$current_mid = Context::get('mid');
$load_recent_posts = in_array($current_mid, array('index', 'main', 'home'));
}
<!--@if($load_recent_posts)-->
{@
// 최신 게시물 로드
$args = new stdClass();
$args->module_srl = 123;
$args->list_count = 5;
$oDocumentModel = getModel('document');
$output = $oDocumentModel->getDocumentList($args);
$recent_posts = $output->data;
}
<div class="recent-posts-widget">
<!-- 위젯 내용 -->
</div>
<!--@end-->
💡 주의사항¶
- 메모리 사용량: 대량의 데이터 조회 시 메모리 사용량 주의
- 보안: 사용자 입력값을 직접 쿼리에 사용할 때 SQL 인젝션 방지
- 성능: 복잡한 쿼리는 캐싱 필수
- 유지보수: 코드 가독성을 위해 적절한 주석 추가