영원한사랑

페이징 함수

인터넷정보2007. 12. 4. 10:03
일반적인것과 그룹화 한 것 두가지 샘플이 있으니 보시면 아실거 같고

리팩토링은 알아서 하시길 바랍니다.
버그있음 댓글달아주세요 (그룹화 해본적이 없어 이런상으로 계산된거라 제대로 나오는지는 모르겠습니다.)

본 코드는 아무렇게가 갖다 쓰심 됩니다.


<?php
// vim600: ts=4 sw=4

class C
{
// constants
    const ERR_PAGING_ROW                    = 10001;
    const ERR_PAGING_SCALE                  = 10002;
    const ERR_PAGING_PART_INFO_INVALID      = 10003;
    const ERR_PAGING_PART_NO_NOT_INTEGER    = 10004;
    const ERR_PAGING_PART_COUNT_NOT_INTEGER = 10005;

// only static
    private function __construct () {}


/**
    @param array
        int total  : 전체 게시물수
        int page    : 현제 페이지번호
        int row    : 페이지당 게시물 수
        int scale  : 페이징 블럭 (페이지에 보여질 번호판 수)
        string link : page=xxx 를 지외한 모든 링크
            예) aaa.php?a=$a&b=$b&c=$c&page=$page 이런 링크가 필요하다면
                            link = "a=$a&b=$b&c=$c";
        array group : 분할정보 (division 정보) 미사용시 필요없음
            int no => int count
    @param part : boolean - 데이타를 group(division) 화 하는지의 여부

    @return array
        total          : 전체 게시물 수
        page            : 현제 페이지 번호
        totalpage      : 총 페이지 수
        prev_link      : 이전 링크
        paging          : 번호판 리스트
        next_link      : 다음 링크
        start_link      : 처음 링크
        end_link        : 마지막 링크
        enable_prev    : 이전페이지 가능한가?
        enable_next    : 다음페이지 가능한가?

        object query    : group 화 정보  (쿼리용 변수)
            int limit  : 쿼리에서 사용할 limit
            int offset  : 쿼리에서 사용할 offset
            array group : 쿼리에서 사용할 group number list
*/

    public static function paging (array $arr, $part = false)
    {
        $total = intval($arr['total']);
        $page = intval($arr['page']);
        $row = intval($arr['row']);
        $scale = intval($arr['scale']);
        $link = $arr['link'];
        $group = $arr['group'];

        if($link) $amp = '&';

        if($row < 1)
            throw new Exception (self::ERR_PAGING_ROW);
        if($scale < 1)
            throw new Exception (self::ERR_PAGING_SCALE);

        if($page < 1) $page = 1;
        $totalpage = ceil($total / $row);
        if($page > $totalpage) $page = $totalpage;

        if($total > 0) {
            $start = (intval($page / $scale) * $scale) + 1;
            if(!($page % $scale)) $start -= $scale;
            $end = $start + $scale - 1;
            if($end > $totalpage) $end = $totalpage;
            $prev = $start - $scale;
            $next = $start + $scale;
        }

        for($i = $start; $i <= $end; $i++)
            $paging_loop[] = array('page_num' => $i,
                                  'page_link' => "page=".$i.$amp.$link);

        $count = count($paging_loop);
        if($count > 0) $paging_loop[$count-1]['end'] = 1;


        $limit = $row;
        $offset = ($page - 1) * $row;

        if(!$part) {
            $_grp->limit = $limit;
            $_grp->offset = $offset;
        }
        else {
            if(!is_array($group))
                throw new Exception(self::ERR_PAGING_PART_INFO_INVALID);

            try {$_grp = self::_make_query_info($group, $limit, $offset); }
            catch (Exception $e) { throw $e; }
        }

        $arr = array('total' => $total,
                    'page' => $page,
                    'totalpage' => $totalpage,
                    'prev_link' => 'page='.$prev.$amp.$link,
                    'paging' => $paging_loop,
                    'next_link' => 'page='.$next.$amp.$link,
                    'start_link' => 'page=1'.$amp.$link,
                    'end_link' => 'page='.$totalpage.$amp.$link,
                    'enable_prev' => ($page > $scale) ? true : false,
                    'enable_next' => ($end < $totalpage) ? true : false,

                    'query' => $_grp
          );

        return $arr;
    }

    private static function _make_query_info(array $grp, $limit, $offset)
    {
        $start = $offset;
        $end = $offset + $limit;

        $sum = 0;
        $found = false;
        $pos = array();
        $_offset = 0;

        foreach($grp as $part => $count) {
            if(!is_int($part) || $part < 1)
                throw new Exception(self::ERR_PAGING_PART_NO_NOT_INTEGER);
            if(!is_int($count))
                throw new Exception(self::ERR_PAGING_PART_COUNT_NOT_INTEGER);

            $sum += $count;

            if($sum > $start) $found = true;
            if($found) {
                $pos[] = $part;
                if(!$_offset) $_offset = $offset + $count - $sum;
            }
            if($sum >= $end) break;
        }

        if(!is_array($pos))
            throw new Exception(self::ERR_PAGING_PART_INFO_INVALID);


        $group->group = $pos;
        $group->offset = $_offset;
        $group->limit = $limit;

        return $group;
    }

    public static function get_errmsg ($const)
    {
        switch($const) {
            case self::ERR_PAGING_ROW:
                return '페이지당 출력수를 셋팅해 주세요';
            case self::ERR_PAGING_SCALE:
                return '페이징 블럭을 셋팅해 주세요';
            case self::ERR_PAGING_PART_INFO_INVALID:
                return '분할정보가 없거나 잘못되었습니다.';
            case self::ERR_PAGING_PART_NO_NOT_INTEGER:
                return '분할번호가 숫자가 아니거나 없습니다.';
            case self::ERR_PAGING_PART_COUNT_NOT_INTEGER:
                return '해당분할그룹의 정보가 숫자가 아닙니다.';
            default: return '알수 없는 에러입니다.';
        }
    }
}

// example1 - 그룹화 하지 않은 경우
$arr = array('total' => 5,
            'page' => 1,
            'row' => 10,
            'scale' => 10);

try {$paging = C::paging($arr); }
catch (Exception $e) {
    print 'LINE: '.$e->getLine().' '
          .C::get_errmsg($e->getmessage());
    exit;
}

// pgsql 에서는 limit offset 이 limit $limit offset $offset
// mysql 에서는 limit $offset,$limit
// oracle 에서는 RN between ($offset + 1) and ($offset + $limit)
// 또는 각자 알아서 영역을 구하시길
$query = "select xxxxx from xxxx order by xxx "
        ."limit ".$paging['query']->limit." offset ".$paging['query']->offset;

$tpl->assign($paging);


// example2 - 그룹화 할 경우 (division 사용시)
// 앞은 분할번호 뒤는 갯수
// 최신정보부터 뒤집어 넣습니다.
$division = array(5 => 205,
                  4 => 5000,
                  3 => 5029,
                  2 => 4800
  );

$arr = array('total' => 15034,
            'page' => 22,
            'row' => 10,
            'scale' => 10,
            'group' => $division);

try {$paging = C::paging($arr, true); }
catch (Exception $e) {
    print 'LINE: '.$e->getLine().' '
          .C::get_errmsg($e->getmessage());
    exit;
}

$query = "select xxxxx from xxxx "
        ."where xxxx "
          ."and division in (".implode(',', $paging['query']->group).") "
        ."order by xxx "
        ."limit ".$paging['query']->limit." offset ".$paging['query']->offset;

$tpl->assign($paging);

?>

펌:http://www.phpschool.com/gnuboard4/bbs/board.php?bo_table=tipntech&wr_id=57690&page=1