서울 N타워 철탑

입사 기념으로 올라가 본 남산 N 타워 철탑

내려다보면 이렇다. 날씨 좋네~

이것은 서울에서 가장 높은 화장실

베를린까지는 8,142.17 km 라고 합니다. 5km/h 로 걸어가면 대략 1600시간이니 두달만 걸으면 되나 했더니 -_-; 헤엄도 쳐야하네.
그냥 비행기 타고 가련다.

by mine | 2008/03/17 22:33 | 트랙백 | 덧글(0)

잠실 - 동남아 - Oriental Spoon

일요일 저녁에 간 곳은 잠실에 새로 생긴 Oriental Spoon.

압구정에 생겨서 잠시 입에 오르내리더니 어느 새 서초 분당 신사에 잠실점까지 생겨버렸다.
어디를 가볼가 고민하다가 주차도 되고 예약도 된다고 해서 그냥 새로 생긴 잠실점에 가보기로 하고 전화를 했다.

홈페이지(
http://www.oritentalspoon.com)에는 분명 '예약가능' 이라고 되어 있는데
"저희는 예약은 안 받는데요~"
뭐냐 -_-;
뭐 당일 예약이라 큰 기대도 안 했다만, 그렇다면 그냥 가도 된다는 말이로구나 해서 일단 가보기로 했다.

석촌호수 앞에 새로 생긴 '빈' 건물 1층에 홀로 문을 열고 있다.
1월에 오픈했다는데 지하 주차장은 아직 관리도 하지 않고 있어서 그냥 주차하면 된다. 근처에 놀러와도 그냥 여기 주차하면 될 듯. 아직은 주차공간이 넉넉하지만, 건물 입주가 끝나면 좀 부족할 것 같았다.

하여간, 7시쯤 방문했는데 빈 자리가 있어서 바로 앉을 수 있었다.

태국/ 베트남/ 인도네시아/ 일본/ 중국 음식을 모아놨다고 하는데, 솔직히 그다지 끌리는 메뉴는 별로 없었다.
(메뉴는 홈페이지 참조)

일단 미 고랭 (인도네시아어로 '미'는 noodle, '고랭'은 'fried') 과 명란 파스타를 주문.
오. 엄청 빨리 나온다.
중국집에서 미리 면 뽑아놨다가 짜장만 얹어서 주는 분위기랄까? ㅎㅎ


단품으로 두개만 시켰더니 엄청 썰렁하다.
사진으로 봐도 약간 그렇긴 하지만 실제로 나온 음식은 ㅠㅠ 너무 없어보여서 마음이 다 아플 정도.
별로 배가 고프지 않았는데도 뭔가 한두개 더 시켜야 하는 것 아닌가 하는 생각이 들었다. 명란 파스타에 흩뿌려진 김이 애처로와...

미 고랭은 먹을만하긴 했는데 너무 짰다.
여기서 식사하면서 물을 다섯 컵이나 들이켰음. -_-;
그리고 볶음면이라는게 뭐... 조리하는 동네, 사람마다 다 맛이 다르기는 하겠지만, 인도네시아에서 먹어봤던 맛과는 무척 달랐고,  숙주 넣은 쟁반짜장이라고 하는게 더 어울릴 듯?
명란 파스타는... 뭐랄까... 음... 그냥... 특이했다. ㅎㅎ

아주 맛이 없다거나 하진 않아서 그럭저럭 먹고 왔다만, 미 고랭 한접시에 만원이 넘는 것도 그렇고, 만이천원짜리 파스타로는 솔직히 많이 아쉬웠다.

매장에 자리는 인사동 뽀모도로처럼 따닥따닥 붙어있지는 않지만, 그렇다고 분리되어 있지도 않아서 약간 산만한 정도?
그냥 편한 식사라면 무난하겠으나 분위기가 필요한 자리에는 추천할만 하지 못하다. 물론 이건 잠실점 이야기.

그래도 메뉴의 가격은 부가세 포함.
난 부가세 별도로 표시한 것 보면 손님을 우롱하는 것 같아서 싫더라. 원숭이 취급 하는 것 같아서. ㅎㅎ

카메라를 안 가지고 가서 핸드폰으로 몇 장 찍었는데, 역시 별로네~ 하지만 실제로 보기도 이것과 별로 다르지 않았음 : )

by mine | 2008/03/17 09:14 | | 트랙백 | 덧글(0)

헨리 제임스 - 나사의 회전

Henry James - The Turn of the Screw (1898)

'나사의 회전' 이라는 제목은 도입부에서 앞으로 펼쳐질 이야기를 소개하면서 등장한다.


"만일 어린아이 하나가 나사를 한 번 더 죄는 효과를 낸다면 어린아이가 둘일 경우 어떻게 되겠어요?"

뭐 -_-; 결국 이 이야기에는 애가 두 명 나오니 한 명 나오는 이야기보다 두배 더 무시무시하다. 이런 어처구니 없는 제목 되시겠다.

원래 글이 이런건지 번역이 엉망인건지 집중하기 무척 어려웠다. 번역하신 최경도씨는 '한국 헨리 제임스 학회' 회장까지 하셨다는 분이니 원 글이 이모냥이라고... 믿어도 될까?

"난 무척이나 동의해요. 지난번 그리핀 씨가 말한 유령 이야기든 무엇이든. 그토록 여린 어린아이에게 맨 먼저 유령이 나타난 게 각별한 기미가 있다는 거 말이오. 하지만 내가 알기로 어린아이와 관련된 감칠 듯한 이야기치고 그게 처음 일어난 건 아닐 거에요."

젠장. 이게 도대체 무슨 소리냔 말이지.

하여간, 시골 목사 딸로 자란 젊은 여성이 가정교사로 들어가서 순진무구해보이는 두 아이들을 맡게 되는데, 사실은 이 아이들이 유령을 보고 있으면서도 아무것도 모르는 척 하고 있었다. 뭐 이런 이야기인데, 원래대로라면 이 가정교사의 불안한 심리와 음울한 분위기, 혼란스러움 같은게 막 잘 표현이 되었어야 할텐데, 도무지... -_-;

사실 arial에게 빌려서 읽기 시작한 지는 두달 쯤 되어가는데, 반쯤 읽다가 난잡함(?)을 견디지 못하고 던져놨다가 마침 며칠 전에 읽은 온다 리쿠 소설에서 헨리 제임스 이야기가 나오기에 다시 한번 마음을 다잡고 끝내버렸다.
역시 원작과 번역본은 다른 작품이라고 봐야한다는 생각을 하게 되는 책.

by mine | 2008/03/15 13:15 | | 트랙백(1) | 덧글(0)

HABTM Pagination on CakePHP 1.2x

게시판 따위를 만들 때마다 항상 귀찮게 하는 pagination 작업을 CakePHP 1.2 에서는 paginator helper 를 통해서 가볍게 지원해준다.

Post 를 페이지별로 보여주고 싶을 때, 간단히 몇줄로 작업 끝이다.

class PostsController extends AppController {
  
    var $paginate = array( 'limit' => 5, 'order' => array( 'Post.created' => 'desc' ) );

    function idex()
    {
        $rs = $this->paginate( 'Post', array( 'Post.status' => '>0' ) );
        debug( $rs ); exit;
    }
}


그런데, 여기에 HABTM association 이 들어가게 되면 문제가 좀 더 복잡해진다.

class Post extends AppModel {
    var $hasAndBelongsToMany = array( 'Tag' => array( 'conditions' => 'PostsTag.status > 0' ) );
}


이렇게 Tag 과 HABTM 관계를 정의해놓고 위의 index 를 그대로 호출하면 아름답게 Post 에 붙은 Tag 들이 끌려 나온다.

Array
(
    [0] => Array
        (
            [Post] => Array
                (
                    [id] => 1
                    [status] => 1
                    [created] => 2007-11-18 23:49:59

                    [text] => hello
                )
            [Tag] => Array
                (
                    [0] => Array
                        (
                            [id] => 1
                            [text] => testTag
                            [PostsTag] => Array
                                (
                                    [post_id] => 1
                                    [tag_id] => 1
                                    [status] => 1
                                )
                        )
                    [1] => Array
                        (
                            [id] => 13
                            [text] => hello
                            [PostsTag] => Array
                                (
                                    [post_id] => 1
                                    [tag_id] => 13
                                    [status] => 1
                                )
                        )
            )
)

뭐 아직까지는 별다른 작업 없이도 원하는 결과를 얻을 수 있다.

참고로 이 때 실제로 수행되는 query 는 아래와 같다

SELECT COUNT(*) AS `count` FROM `posts` AS `Post` WHERE `Post`.`status` > 0        // pagination 을 위한 count 처리
SELECT `Post`.`id`, `Post`.`status`, Post`.`created`, `Post`.`text` FROM `posts` AS `Post` WHERE `Post`.`status` > 0 ORDER BY `Post`.`created` desc LIMIT 5
SELECT `Tag`.`id`, `Tag`.`text`, `PostsTag`.`post_id`, `PostsTag`.`tag_id`, `PostsTag`.`status` FROM `tags` AS `Tag` JOIN `posts_tags` AS `PostsTag` ON (`PostsTag`.`post_id` IN (1, 2) AND `PostsTag`.`tag_id` = `Tag`.`id`) WHERE `PostsTag`.`status` > 0
    // 각 Post 에 해당하는 Tag 검색


자, 여기까지는 무난하다.
그럼 이번에는 Tag 별 검색을 해보도록 하자.
원하는 결과는 아래와 같다

INDEX BY 'testTag'

Post1
    tags : testTag, hello, tag1

Post4
    tags : testTag

Post11
    tags : asdf test testTag


즉, 간단하게 말하면 특정 tag 을 포함하는 게시물의 리스트를 보여주는 것이다.

사실 이것을 처리하는 데에는 여러가지 방법이 있다.

posts_tags 테이블에서 tag_id 로 query 한 결과를
$this->paginate( 'Post', array( 'Post.status' => '>0', 'Post.id' => 'IN (' . implode( ', ', $list ) . ')' ) );
해서 처리해도 되지만, 뭔가 깔끔해보이지 않는다.

paginate HABTM 을 구글해보면 몇가지 글이 검색된다.
참고할만한 것들은 이것
http://cakebaker.42dh.com/2007/10/17/pagination-of-data-from-a-habtm-relationship/
http://www.cricava.com/blogs/index.php?blog=6&title=modelizing_habtm_join_tables_in_cakephp_&more=1&c=1&tb=1&pb=1

두번째 링크에 있는 mariano iglesias 의 방법을 살짝 바꿔서 써보도록 하자.
여기 나온 것은 일단 paginate 를 사용하지 않고 findAll 만 호출했고, 각 게시물별 tag 이 결과에 포함되어 있지 않기도 하고, 하여간 직접 쓰기에는 적당하지 않다.

function tags( $tagid )
{
    $rs = $this->paginate( 'PostsTag', array( 'PostsTag.tag_id' => $tagid ) );
    debug( $rs );
}


아이쿠 $paginate 를 정의해준 데서 사용한 'order' => array( 'Post.created' => 'desc' )  부분이 문제다. 실제 쿼리를 보면

SELECT COUNT(*) AS `count` FROM `posts_tags` AS `PostsTag` WHERE `PostsTag`.`tag_id` = 17
SELECT `PostsTag`.`post_id`, `PostsTag`.`tag_id`, `PostsTag`.`status` FROM `posts_tags` AS `PostsTag` WHERE `PostsTag`.`tag_id` = 17 ORDER BY `Post`.`created` desc LIMIT 5


이렇게 되어있다. PostsTag 과 Post 간의 관계가 정의되어 있지 않아서 생기는 문제다.
살짝
$this->paginate = array( 'limit' => 2 );
라고 끼워넣어보면 결과가 나오기는 하지만, 역시 원하는 결과는 아니다.

자, 그러면 여기서 PostsTag 과 Post 간의 관계를 정의해버리면 되겠다.
$this->Post->PostsTag->bindModel( array( 'belongsTo' => array( 'Post' ) ) );
$rs = $this->paginate( 'PostsTag', array( 'PostsTag.tag_id' => $tagid ) );


어라? 여전히 똑같은 에러가 나온다. 하지만 실제 쿼리는 살짝 다르다.

SELECT COUNT(*) AS `count` FROM `posts_tags` AS `PostsTag` LEFT JOIN `posts` AS `Post` ON (`PostsTag`.`post_id` = `Post`.`id`) WHERE `PostsTag`.`tag_id` = 17
SELECT `PostsTag`.`post_id`, `PostsTag`.`tag_id`, `PostsTag`.`status` FROM `posts_tags` AS `PostsTag` WHERE `PostsTag`.`tag_id` = 17 ORDER BY `Post`.`created` desc LIMIT 5


두번째 쿼리는 동일하지만 첫번째 쿼리에 posts 테이블이 (바라던 대로) left join 되었다.
bindModel(), unbindModel()은 이후에 시행되는 쿼리 한번에 대해서만 유효한데, paginate() 안에서 쿼리를 두번 하기 때문에 두번째 쿼리에는 적용이 되지 않기 때문이다.

원인을 알았으니 다시 해보자.

$this->Post->PostsTag->bindModel( array( 'belongsTo' => array( 'Post' ) ), false );
$rs = $this->paginate( 'PostsTag', array( 'PostsTag.tag_id' => $tagid ) );


bindModel() 에서 두번째 인자로 false 를 주면 한번 쿼리 한 이후에도 bind/ unbind 가 해제되지 않는다.
자, 이제 결과가 나왔다.

Array
(
    [0] => Array
        (
            [PostsTag] => Array
                (
                    [post_id] => 34
                    [tag_id] => 17
                    [status] => 1
                )

            [Post] => Array
                (
                    [id] => 34
                    [status] => 1
                    [created] => 2007-11-18 23:49:59
                    [modified] => 2007-11-20 01:28:41
                    [text] => 그렇다.
                )
        )

    [1] => Array
        (
            [PostsTag] => Array
                (
                    [post_id] => 29
                    [tag_id] => 17
                    [status] => 1
                )

            [Post] => Array
                (
                    [id] => 29
                    [status] => 1
                    [created] => 2007-11-17 20:08:35
                    [text] => 에헤라 얼씨구 절씨구 차차차 얼쑤~
                )
        )
)

자, 원하던대로 TAG 17 을 가지는 POST (29, 34) 가 반환되었다.
아니 그런데 잘 살펴보니, tag 은 어디갔어?

위의 mariano iglesias 의 방법대로
$this->Post->PostsTag->bindModel( array( 'belongsTo' => array( 'Post', 'Tags ) ), false );
해주면 어떨까?

Array
(
    [0] => Array
        (
            [PostsTag] => Array
                (
                    [post_id] => 34
                    [tag_id] => 17
                    [status] => 1
                )

            [Post] => Array
                (
                    [id] => 34
                    [status] => 1
                    [created] => 2007-11-18 23:49:59
                    [text] => 그렇다.
                )

            [Tag] => Array
                (
                    [id] => 17
                    [text] => 테스트
                )
        )

    [1] => Array
        (
            [PostsTag] => Array
                (
                    [post_id] => 29
                    [tag_id] => 17
                    [status] => 1
                )

            [Post] => Array
                (
                    [id] => 29
                    [status] => 1
                    [created] => 2007-11-17 20:08:35
                    [text] => 에헤라 얼씨구 절씨구 차차차 얼쑤~
                )

            [Tag] => Array
                (
                    [id] => 17
                    [text] => 테스트
                )
        )
)

오. tag 정보까지 나왔다.
그런데 잘 살펴보면 이것은 원하는 결과가 아니다. 그 게시물에 포함된 모든 tag 가 반환된 것이 아니라 id=17 인 tag 정보만 포함되어서 나왔다.
자, 그럼 원하는 결과를 얻기 위해서는 어떻게 해야할까? 아래와 같이 가볍게 recursive 만 하나 더해주면 된다.

$this->Post->PostsTag->bindModel( array( 'belongsTo' => array( 'Post' ) ), false );
$this->Post->PostsTag->recursive = 2;
$rs = $this->paginate( 'PostsTag', array( 'PostsTag.tag_id' => $tagid ) );


결과는 아래와 같다

Array( 
[0] => Array (
[PostsTag] => Array (
[post_id] => 34
[tag_id] => 17
[status] => 1
)
[Post] => Array (
[id] => 34
[status] => 1
[created] => 2007-11-18 23:49:59
[text] => 그렇다.
[Tag] => Array (
[0] => Array (
[id] => 2
[text] => asdf
[PostsTag] => Array (
[post_id] => 34
[tag_id] => 2
[status] => 1
)
)
[1] => Array (
[id] => 17
[text] => 테스트     
[PostsTag] => Array (
[post_id] => 34
[tag_id] => 17
[status] => 1
)
)
)
)
)
[1] => Array (
[PostsTag] => Array (
[post_id] => 29
[tag_id] => 17
[status] => 1
)
[Post] => Array (
[id] => 29
[status] => 1
[created] => 2007-11-17 20:08:35
[text] => 에헤라 얼씨구 절씨구 차차차 얼쑤~
[Tag] => Array (
[0] => Array (
[id] => 16
[text] => 타령     
[PostsTag] => Array (
[post_id] => 29
[tag_id] => 16
[status] => 1
)
)
[1] => Array (
[id] => 17
[text] => 테스트     
[PostsTag] => Array (
[post_id] => 29
[tag_id] => 17
[status] => 1
)
)
)
)
)
)

자, 이제는 정말 원하는 결과가 나왔다.
Tag 밑에 필요없는 PostsTag 까지 따라나오긴 했지만, 이건 그냥 무시하면 된다.

실제 query는 아래와 같다.

SELECT COUNT(*) AS `count` FROM `posts_tags` AS `PostsTag` LEFT JOIN `posts` AS `Post` ON (`PostsTag`.`post_id` = `Post`.`id`) WHERE `PostsTag`.`tag_id` = 17
SELECT `PostsTag`.`post_id`, `PostsTag`.`tag_id`, `PostsTag`.`status`, `Post`.`id`, `Post`.`status`, `Post`.`created`,  `Post`.`text` FROM `posts_tags` AS `PostsTag` LEFT JOIN `posts` AS `Post` ON (`PostsTag`.`post_id` = `Post`.`id`) WHERE `PostsTag`.`tag_id` = 17 ORDER BY `Post`.`created` desc LIMIT 5
SELECT `Post`.`id`, `Post`.`status`, `Post`.`created`, `Post`.`text` FROM `posts` AS `Post` WHERE `Post`.`id` = 34
SELECT `Tag`.`id`, `Tag`.`text`, `PostsTag`.`post_id`, `PostsTag`.`tag_id`, `PostsTag`.`status` FROM `tags` AS `Tag` JOIN `posts_tags` AS `PostsTag` ON (`PostsTag`.`post_id` IN (34) AND `PostsTag`.`tag_id` = `Tag`.`id`) WHERE `PostsTag`.`status` > 0
SELECT `Post`.`id`, `Post`.`status`, `Post`.`created`, `Post`.`text` FROM `posts` AS `Post` WHERE `Post`.`id` = 29
SELECT `Tag`.`id`, `Tag`.`text`, `PostsTag`.`post_id`, `PostsTag`.`tag_id`, `PostsTag`.`status` FROM `tags` AS `Tag` JOIN `posts_tags` AS `PostsTag` ON (`PostsTag`.`post_id` IN (29) AND `PostsTag`.`tag_id` = `Tag`.`id`) WHERE `PostsTag`.`status` > 0

recursive 때문에 검색된 Post 갯수 * 2 만큼 쿼리 수가 늘어나는 문제는 있지만, 일단 결과는 무난히 처리되었다.
만약 이렇게 쿼리 수가 늘어나는 것이 싫다면 recursive=1 의 결과를 취합해서 해당 Post 와 연관되는 Tag 들을 모두 검색하여 다시 연관지어주는 작업을 손으로 해줘야 한다.
어느쪽이 좋을지는 각자의 판단대로 : )

by mine | 2007/11/22 11:05 | | 트랙백 | 덧글(0)

◀ 이전 페이지 다음 페이지 ▶