WordPress에서 제공하는 클래스인 WP_Query는 wordpress의 컨텐츠(Post, Page, Custom content etc.)를 쉽게 불러 사용할 수 있도록 도와준다. Widget이나 테마 등에서 컨텐츠 목록을 제공할 필요가 있을 때 편리하게 사용할 수 있다.

<?php    
// The Query
$the_query = new WP_Query( $args );

// The Loop
while ( $the_query->have_posts() ) {
    $the_query->the_post();
    echo '<li>' . get_the_title() . '</li>';
}

자세한 내용은 WordPress에서 제공하는 WP_Query 문서에서 확인할 수 있다.

WP_Query에서는 데이터를 가져올 때 array의 형태로 properties를 추가해 활용한다. 한 페이지에서 WP_Query를 여러번 사용할 수도 있는데 이런 경우, 재사용성을 높이기 위해 이전의 설정들이 저장되어 의도하지 않은 데이터가 출력될 때가 있다. 그런 경우를 위해 설정을 초기화 하는 함수인 wp_reset_postdata()가 제공된다.

<?php    
// The Query
$the_query = new WP_Query( $args );

// The Loop
while ( $the_query->have_posts() ) {
    $the_query->the_post();
    echo '<li>' . get_the_title() . '</li>';
}
wp_reset_postdata();

$new_query = new WP_Query( $new_args );

wp_reset_postdata()를 사용했는데도 입력한 properties가 무시되는 등 의도한 대로 동작하지 않는 경우가 있다. 이 경우는 WP_Query 클래스에서 포스트를 가져올 때 pre_get_posts hook을 실행하는데 이 포인트에 query 결과를 조작하는 action이 등록되어 있을 가능성이 높다.

이 hook을 잘못 건들면 대다수의 플러그인과 테마에서 문제가 발생할 수 있기 때문에 만지지 않는걸(should not) 권장한다. Woo Commerce와 같은, 규모가 큰 플러그인은 구현 편의를 위해 이 hook을 사용해 개발하는 경우가 있다. 즉, WP_Query가 제대로 동작하지 않는다면 다른 플러그인이나 테마에서 pre_get_posts를 조작하고 있는지 확인해야 한다.

<?php

wp_reset_postdata();

global $evil_class;
remove_action( 'pre_get_posts', array( $evil_class, 'inject_get_posts' ) );

// The Query
$the_query = new WP_Query( $args );

// The Loop
while ( $the_query->have_posts() ) {
    $the_query->the_post();
    echo '<li>' . get_the_title() . '</li>';
}

// Recover
wp_reset_postdata();
add_action( 'pre_get_posts', array( $evil_class, 'inject_get_posts' ) );

PHP에서의 DateTime은 늘 문자열로 처리되어 strtotime()를 엄청나게 사용하게 되고, 기간 비교를 위해 timestamp를 직접 다뤄야 하는 번거로움 등 불편함을 다 적기에 시간이 부족할 정도다. 5.2.0 이후 지원되는 DateTime은 다른 언어들과 비교하면 아직 모자란 부분이 많이 있지만 그래도 쓸만한 구석은 거의 다 갖추고 있다. 모든 시간을 문자열로 다뤄 데이터의 의미를 제대로 살리지 못했던 과거에 비해, 더 읽기 쉽고 다루기 편한 코드를 작성하는데 도움이 된다.

PHP 5.2.0 이후 DateTime Class가 지원되기 시작했으며 버전이 계속 올라가면서 다양한 DateTime 관련 Class가 추가되었다.

  • DateTime (PHP 5 >= 5.2.0)
  • DateTimeImmutable (PHP 5 >= 5.5.0)
  • DateTimeInterface (PHP 5 >= 5.5.0)
  • DateTimeZone (PHP 5 >= 5.2.0)
  • DateInterval (PHP 5 >= 5.3.0)
  • DatePeriod (PHP 5 >= 5.3.0)

짧은 요약

  • 버전이 5.3.0 이상은 되야
  • 문자열로 DateTime을 사용하는 것에 비해 훨씬 편리
  • 시간 비교가 편리해짐
  • 타임존 변경이 비교적 편리해짐

살펴보기

DateTime 클래스는 문자열로 바로 선언해 사용할 수 있으며 setDate(), setTime() 같은 메소드도 지원한다. 1

$now = new DateTime();
$yesterday = new DateTime('yesterday');
$birthday = new DateTime('1988-06-08');

출력은 기존에 date() 함수를 사용하던 것과 유사하다. format() 메소드를 통해 문자열 format을 지정해 출력할 수 있다.

print $now->format('Y-m-d H:i:s');

선언한 DateTime에 시간을 더하거나 뺄 때는 DateInterval 클래스를 활용할 수 있다. 2

$date = new DateTime('2013-12-24');

$term = new DateInterval('P100D');
$date->sub($term);
print $date->format('Y-m-d'); // 2013-09-15

$date->add(new DateInterval('P1M10D'));
print $date->format('Y-m-d'); // 2013-10-25

또한 기간끼리의 비교도 간편하게 지원한다. diff()를 활용해 기간을 비교할 수 있다. 3diff()DateInterval 객체를 반환한다.

$now = new DateTime();
$birthday = new DateTime("1988-06-08");
$diff = $now->diff($birthday);
print $diff->days;

DateTime으로 생성되는 시간은 시스템에 설정된 시간대를 기준으로 생성된다. 4DateTimeZone 클래스를 이용해 시간대를 지정할 수 있으며 지정할 때는 setTimezone() 메소드를 이용하면 된다.

$date = new DateTime("now");
print $date->format("c");
$date->setTimezone(new DateTimeZone("Asia/Seoul"));
print $date->format("c");
$us_date = new DateTime("now", new DateTimeZone("US/Eastern"));
print $date->format("c");

주의해야 할 부분은 일광절약시간을 사용하는 지역이다. 일광절약시간(Daylight saving time)을 사용하는 경우 1년에 특정 시간이 2번 나타나거나 아예 안나타나는 시간이 존재한다. 예를 들면 호주 멜번에서는 2014년 4월 6일 일광절약시간이 종료되는데 그로 인해 새벽 2시가 2번 나타나야 한다.

$term = new DateInterval("PT1H");
$au_date = new DateTime("2014-04-06 00:00:00",
                        new DateTimeZone("Australia/Melbourne"));

print $au_date->format("c");  // 2014-04-06T00:00:00+11:00
$au_date->add($term);
print $au_date->format("c");  // 2014-04-06T01:00:00+11:00
$au_date->add($term);
print $au_date->format("c");  // 2014-04-06T02:00:00+10:00

일광절약시간 해제는 정상적으로 되지만 2시는 두번 나타나지 않는다. 이런 문제는 시간을 UTC로 다뤄야 해결할 수 있다.

$term = new DateInterval("PT1H");
$utc = new DateTimeZone("UTC");
$melb = new DateTimeZone("Australia/Melbourne");

$utc_date_before = new DateTime("2014-04-05 15:00:00", $utc);
$utc_date_before->setTimezone($melb);

$utc_date_after = new DateTime("2014-04-05 16:00:00", $utc);
$utc_date_after->setTimezone($melb);

print $utc_date_before->format("c");  // 2014-04-06T02:00:00+11:00
print $utc_date_after->format("c");   // 2014-04-06T02:00:00+10:00

이런 경우 DateTimeImmutable 클래스를 사용하면 좀 더 편리하다. 이 클래스는 객체를 변경하지 않는 대신 새 객체를 반환한다.

$term = new DateInterval("PT1H");
$utc = new DateTimeZone("UTC");
$melb = new DateTimeZone("Australia/Melbourne");

$utc_date = new DateTimeImmutable("2014-04-05 15:00:00", $utc);
$utc_date_after = $utc_date->add($term);

print $utc_date->setTimezone($melb)->format("c");
                                        // 2014-04-06T02:00:00+11:00
print $utc_date_after->setTimezone($melb)->format("c");
                                        // 2014-04-06T02:00:00+10:00

마지막으로 DatePeriod 클래스는 반복문에서 유용하게 사용되는 클래스다. 일정 기간동안 특정 주기를 반복적으로 처리할 때 유용한 클래스며 5.0.0 에서 추가된 Traversable 내장 클래스를 상속하는 클래스다. 특히 주기를 상대적인 포맷(Relative formats)을 사용해 작성할 수 있다.

$begin = new DateTime('2013-01-01 00:00:00');
$end = new DateTime('2013-12-31 23:59:59');
$interval = DateInterval::createFromDateString('next monday');

$period = new DatePeriod($begin, $interval, $end, DatePeriod::EXCLUDE_START_DATE);

foreach ($period as $dt){
    echo $dt->format("l Y-m-d") . "\n";
}

시간을 다루는 편리한 방법, 단 버전이 된다면

이상으로 PHP에서 쉽게 시간을 다룰 수 있도록 하는 클래스인 DateTime을 살펴봤다. 몇 클래스는 5.5.0 이상에서만 지원하고 있기 때문에 바로 사용하긴 어려울 수 있을지도 모르겠다. 하지만 PHP에서 시간을 문자열로 다루는 것은 여전히 번거로운 작업이므로 적극적으로 도입해야 하지 않나 생각이 든다. 환경이 5.3.0 이상이라면 꼭 사용해보도록 하자.

이 글은 PHP 레퍼런스의 datetime 항목을 토대로 정리했다. 자세한 내용은 해당 메뉴얼을 살펴보면 확인할 수 있다.

Footnotes

  1. DateTime class http://www.php.net/manual/en/class.datetime.php

  2. DateInterval class http://www.php.net/manual/en/class.dateinterval.php

  3. DateTime diff method http://www.php.net/manual/en/datetime.diff.php

  4. date_default_timezone_get() 함수를 통해 현재 설정된 타임존을 확인할 수 있다.

근래 들어서는 공개적으로 하는 작업은 아니지만 잔잔하게 프로토타이핑은 꾸준히 하고 있는데 flasksqlalchemy 조합으로 진행하고 있었다.

  • flask는 micro web framework이며 micro 답게 간단하게 작성 가능해 생각나는 대로 작성하기 편리
  • sqlalchemy는 class 정의 만으로 db를 쉽게 구성하고 코드와 스키마를 두번 작성하는 수고를 줄여주는, 짱짱 좋은 ORM

호기심으로 로컬의 php를 이번달에 공개한 5.5.5으로 업데이트 하면서 micro framework이 없을까 찾아봤더니 비슷한 컨셉의 프레임워크가 많이 보여 간단하게 정리해봤다. (sqlalchemy를 대안으로 사용할 php orm은 제대로 찾아보지 못했다.)

찾아보니 생각보다 많은 편이었고 flask에서 이용한 파이썬의 delegate과 같은 feature는 php에 존재하지 않기 때문에 다양한 방식으로 구현되어 있었다. 특히 php에서 익명함수(Anonymous function)는 5.3.0 이후 제공되고 있기 때문에 이를 기준으로 지원 여부를 살펴보는 것도 도움이 된다. 1

대다수 micro framework는 Composer라는 의존성 관리도구를 설치하길 권장한다. Composer 시작하기 문서를 살펴보면 도움이 된다.

Slim

Slim은 composer를 통해 간편하게 설치할 수 있으며 PHP 5.3.0 이상을 요구한다.

$app = new \Slim\Slim();
$app->get('/hello/:name', function($name){
    echo 'Hello, ' . $name;
});
$app->run();

$app에 인스턴스를 할당할 때 mode, debug 등 다양한 옵션을 넣을 수 있으며 use2를 이용한 스코핑 인젝션 등이 가능하다. 익명함수, 일반함수 두가지 모두 가능하다. Route가 명시적이라 코드 리딩이 더 쉬운 편이다. 자세한 내용은 Slim의 문서 http://www.slimframework.com/ 참고.

Limonade

Limonade http://limonade-php.github.io/는 루비의 Sinatra와 Camping, Lua의 Orbit의 영감으로 만들어진 PHP micro framework이다.

require_once 'vendors/limonade.php';
dispatch('/', 'hello');
  function hello()
  {
      return 'Hello world!';
  }
run();

각 기능을 함수로 선언해 dispatch를 이용해 각 URL에 라우팅 하는 형태로, 직관적인 코드 작성이 가능하지만 동일한 함수명을 사용하지 않도록 주의해야 한다.

Flight

Flight라는 Public class를 이용해 작성해나가는 형태의 framework이다.

require 'flight/Flight.php';

Flight::route('/', function(){
    echo 'hello world!';
});

Flight::start();

사용자가 선언한 인스턴스가 아닌 Flight를 반복적으로 입력해야 해서 별로 좋은 것 같진 않다. Flight http://flightphp.com/

Silex

Silex http://silex.sensiolabs.org/는 앞서 살펴본 Slim과 상당히 유사하며 Symfony2 컴포넌트를 기반으로 한 특징을 가지고 있다.

require_once __DIR__.'/../vendor/autoload.php'; 

$app = new Silex\Application(); 

$app->get('/hello/{name}', function($name) use($app) { 
    return 'Hello '.$app->escape($name); 
}); 

$app->run(); 

Bullet

PHP 5.3+을 요구, 5.4 이상을 추천하는 framework이다. Composer로 패키지 관리가 가능하다.

$app = new Bullet\App();
$app->path('/', function($request) {
    return "Hello World!";
});

echo $app->run(new Bullet\Request());

확장성을 고려해 구현해둔 부분이 많이 보인다. Bullet 문서 참고.

GluePHP

그냥 받아서 압축을 해제하면 바로 사용할 수 있는 micro framework이다. 다른 것들에 비해 가장 생각없이(?) 쉽게 사용할 수 있다.

<?php
    require_once('glue.php');
    $urls = array(
        '/' => 'index'
    );
    class index {
        function GET() {
            echo "Hello, World!";
        }
    }
    glue::stick($urls);
?>

url에 대해 정규표현식으로 지정할 수 있는 특징이 있다. 각각의 메소드를 바인딩 하는 것이 아니라 클래스를 바인딩하며 각 클래스마다 GET(), POST() 등의 메소드를 호출하는 형태다. 3

Footnotes

  1. 사실 대다수의 micro framework는 5.3 이상을 요구한다. 그래도 예전에 비해 php 최근 버전을 지원하는 호스팅이 많이 늘었다.

  2. 익명함수 내부에서 외부의 변수를 이용하기 위해 사용하는 메소드다.

  3. 클래스의 단위를 잘 고려하지 않으면 쉽게 지저분해질 것 같다.

Composer라는 PHP 의존성 관리도구가 있다고 하길래 재빨리 찾아 Getting Started만 발번역했다. npm이나 apt, pip같은 것들과는 닮았지만 다른 부분이 많은데 그만큼 PHP라는 언어에 대한 고민의 흔적을 느낄 수 있다.


Composer는 PHP를 위한 의존성 관리도구다. 이 도구를 사용해 해당 프로젝트에서 요구하는, 의존적인 라이브러리를 선언해 프로젝트에서 설치해 사용할 수 있도록 돕는다.

의존성 관리도구

Composer는 패키지 관리도구가 아니다. 물론 각 프로젝트 단위로 패키지나 라이브러리를 다룬다면 그런 역할을 할 수 있다. 하지만 이 패키지나 라이브러리는 프로젝트 내 디렉토리 단위로 설치된다. (예로 vender) 기본적으로 composer는 절대 전역적으로 사용하도록 설치하지 않는다. 그러므로 의존성 관리도구라고 부른다.

이 아이디어는 새로운 것이 아니며 Composer는 nodejs의 npm이나 ruby의 bundler에 커다란 영감을 얻어 만들어졌다. 그러나 이러한 도구는 PHP에 적합하지 않았다.

Composer가 해결한 문제는 다음과 같다:

a) 프로젝트가 여러개의 라이브러리에 의존적이다 b) 몇 라이브러리가 다른 라이브러리에 의존성이 있다 c) 무엇에 의존성이 있는지 선언할 수 있다 d) Composer는 설치할 필요가 있는 패키지 버전을 찾아 설치한다. (프로젝트 안으로 설치한다는 뜻이다)

의존성 선언

프로젝트를 생성할 때 필요로 하는 라이브러리를 적어줘야 한다. 예를 들어 monolog를 프로젝트에서 사용하기로 결정했다고 치자. 그렇다면 필요로 하는 것은 composer.json 파일을 생성하고 프로젝트의 의존성을 명시적으로 작성해주면 된다.

{
    "require": {
        "monolog/monolog": "1.2.*"
    }
}

시스템 요구사항

Composer는 동작하기 위해 PHP 5.3.2 이상을 요구한다. 또한 몇가지의 php 세팅과 컴파일 플래그를 필수적으로 요구하며 설치할 때 적합하지 않은 부분에 대해 경고해줄 것이다.

소스로부터 패키지를 설치할 때 단순히 zip 압축파일을 받는 대신 어떻게 패키지가 버전관리 되는지에 따라 git, svn 또는 hg가 필요할 것이다.

Composer는 멀티플랫폼을 지원하며 Windows, Linux와 OSX에서 동일하게 동작하도록 만들기 위해 노력하고 있다.

*nix 환경 설치

실행 가능한 composer 다운로드하기

지역 설치 (locally)

Composer를 받기 위해서는 두가지가 필요하다. 첫째로 Composer를 설치하는 것이다. (프로젝트에 Composer를 내려받는다는 의미):

$ curl -sS https://getcomposer.org/installer | php

이 과정은 요구되는 PHP 세팅 몇가지를 확인한 후 composer.phar를 작업 디렉토리에 내려받는다. 이 파일은 Composer 바이너리이며 PHAR(PHP 아카이브)로 PHP를 커맨드 라인으로 실행할 수 있도록 해주는 아카이브 포맷이다.

당신은 Composer를 --install-dir 옵션과 함께 경로 디렉토리를 입력해 특정 디렉토리에 설치가 가능하다 (절대경로와 상대경로 모두 가능):

$ curl -sS https://getcomposer.org/installer | php -- --install-dir=bin

전역 설치 (Globally)

이 파일은 어디든 원하는 곳에 위치할 수 있다. 이 파일의 위치를 PATH 환경변수에 지정된 곳에 넣어두면 전역적으로 사용할 수 있다. unix와 같은 시스템에서 php 없이 실행할 수 있도록 만들 수도 있다.

아래의 명령어는 composer로 시스템 어디에서든 쉽게 실행할 수 있도록 한다:

$ curl -sS https://getcomposer.org/installer | php
$ mv composer.phar /usr/local/bin/composer

노트: 권한 문제가 있다면 mv 부분은 sudo를 이용해 다시 실행한다.

그리고 php composer.phar로 실행하는 대신 composer로 실행하면 된다.

전역 설치 (homebrew를 이용해 OSX에서 설치)

Composer는 homebrew-php 프로젝트의 일부다.

  1. homebrew-php가 아직 설치되지 않았다면 brew를 통해 설치: brew tap josegonzalez/homebrew-php
  2. brew install josegonzalez/php/composer를 실행
  3. composer 명령어로 사용

노트: PHP53 또는 그 이상의 버전이 존재하지 않는다는 에러가 나타나면 brew install php53-intl로 설치한다.

Windows 환경 설치

인스톨러 이용

Composer를 설치하기 가장 쉬운 방법이다.

Composer-Setup.exe 를 내려받아 실행한다. 이 인스톨러는 가장 최신 버전의 Composer를 PATH로 설정된 경로에 설치해 어느 경로에서든 composer 명령어를 사용할 수 있도록 해준다.

수동 설치

PATH 경로로 이동해 설치 스니핏을 실행하여 composer.phar를 내려받는다:

C:\Users\username>cd C:\bin
C:\bin>php -r "eval('?>'.file_get_contents('https://getcomposer.org/installer'));"

노트: 위 내용 중 file_get_contents 함수가 동작하지 않는다면 http 주소로 내려받거나 php.ini에 php_openssl.dll를 활성화한다.

composer.phar를 위한 composer.bat를 생성한다:

C:\bin>echo @php "%~dp0composer.phar" %*>composer.bat

현재 터미널을 닫고 새 터미널에서 아래와 같이 테스트한다:

C:\Users\username>composer -V
Composer version 27d8904

C:\Users\username>

Composer 사용하기

이제 Composer를 사용해 프로젝트에서 의존하고 있는 라이브러리를 내려받는다. composer.json 파일이 현재 디렉토리에 존재하지 않는다면 Basic Usage 챕터로 넘어가도 된다.

의존적인 라이브러리를 내려받기 위해서, install 명령어를 실행한다:

$ php composer.phar install

전역 설치를 했다면 phar 없이 아래와 같이 실행한다:

$ composer install

위에서 예로 들었던 부분에 따라, 위 명령어를 통해 monolog를 vendor/monolog/monolog 디렉토리로 내려받게 된다.

자동 불러오기

라이브러리를 다운받는 것 이외에 Composer는 어떤 라이브러리든 자동으로 적합한 라이브러리를 불러와 사용하도록 돕는다. 자동 불러오기를 사용하려면 단지 아래의 코드를 넣어준다:

require 'vendor/autoload.php';

이제 monolog를 바로 사용할 수 있다. Composer에 대해 더 배우기 위해서는 Basic Usage 챕터를 참고한다.


더 읽을 거리

Xpressengine에서 Composer 문서를 전문 번역했다.

먼저 다음 중 자신에게 해당되는 부분이 있다면 Codeigniter로 옮겨 탈 가치가 충분하다.

  • 반복적인 작업에 자신이 만든 라이브러리(라고 스스로 칭하는 스파게티 소스코드)가 있는 사람
  • 개발 로직과 마크업 요소가 뒤엉켜 있어 뭔가 수정할 일이 있을 때 멍해지는 사람
  • SQL injection 등 각종 보안 문제로 골머리를 썩혔던 사람
  • PHP로 개발하는 사람
  • 관심있게 이 글을 읽고 있는 당신
개인적으로 안봤으면 하는 사람은 아래와 같다.
  • 객체지향 프로그래밍에 대해 관심이 없는 사람
  • PHP를 아직 잘 모르는데 Codeigniter로 배우기 시작하려는 사람

PHP Framework는 사실 뭔가 엄청나고 대단한 것이 아니다. 이미 수많은 개발 언어와 이론들의 방향을 살펴보면 오히려 자연스러운 전개다. PHP Framework는 필연적으로 나타날 요소였지만 이렇게 오랜 시간이 걸렸던 이유는 배우기 쉬운 개발언어라는 오명 하에 고급 언어를 롤 모델로 생산성을 향상 시키는 것에 게을리 해왔던 탓이 아닐까.

기존의 PHP 개발 방식은 하나의 파일에 모든 처리과정이 들어있는 방식이다. 비록 파일을 분리해서 include나 require로 불러오긴 하지만 데이터를 페이지로 가져오는 부분이나 가져온 데이터를 수정, 가공하는 부분, 화면에 출력하는 부분까지 모두 하나의 페이지에서 if나 switch와 같은 구문을 통해 처리를 한다. 이 개발 방식의 단점은 화면과 로직과 데이터를 분리할 수 없어 쉽게 비빔밥이 될 수 있다는 것이다.

이를 보완하기 위해 많은 개발 패턴이 등장하는데 Codeigniter에서 사용하는 패턴은 MVC 패턴이다. 앞서 말한 기존의 개발 방식은 비빔밥이라 예를 들었는데 MVC는 김밥과도 같다고 볼 수 있다.김밥은 나름 분해가 가능하니까! 뭐 꽉꽉 말아버린 김밥이면 분해했을 때 비빔밥처럼 될 수도 있으니 그리 적절하지 못한 비유긴 하지만;

MVC는 모델, 뷰, 컨트롤러의 머릿글자를 모아 만든 조어인데 각각 담당하는 역할이 다르다. 모델은 자료를 찾는 용도, 뷰는 화면에 보여주는 용도, 컨트롤러는 필요한 데이터를 모델에 요청하고 화면에 뿌릴 데이터를 뷰에 보내주는 역할을 한다.

간단하게 메모장을 만든다고 가정을 해보자. 모델에서는, 뷰에서는, 그리고 컨트롤러에서는 무엇이 필요할까? 답은 이 글의 끝에 붙여놓을테니 계속 읽으면서 생각해보자.

물론 말은 간단한데 처음 보는 접할 때는 뜬금없이 나온 이 세 녀석의 용도가 참 모호하다. 특히 내 경우는 그럼 모델과 컨트롤러는 무슨 차이를 가지는 것인가, 왜 분리하는 것인가, 어떤 경계를 가지고 돌아가는 것인가에 대해 상당한 의문을 품었던 기억이 난다. 깊게 생각하지 말고 컨트롤러는 전체를 총괄하고 모델은 데이터베이스 부분을 담당한다고 생각하면 쉽다. (막상 적다보니 왜 분리하는지에 대한 정확한 이유가 떠오르질 않는다;; 말리고 있어!!)

모델은 DB, 뷰는 Front-end, 컨트롤러는 총괄. 반복해서 탁하면 억하고 튀어나올 정도는 되어야 쓰면서 헷갈리지 않는다.

Codeigniter는 약한 MVC 패턴을 채택하고 있어서 사실 모델과 컨트롤러를 혼합해서 써도 되고 컨트롤러를 뷰처럼 써버려도 상관이 없다. 그래도 기왕 MVC 패턴으로 넘어오기로 했으면 MVC 답게 써야 하는 것이 좋지 않을까? (협박..;;)

컨트롤러

  • 메모입력
  • 메모수정
  • 메모삭제
  • 메모목록

모델

  • 메모 입력하기
  • 메모목록 불러오기
  • 메모 삭제하기
  • 메모 수정하기

  • 메모입력/수정
  • 메모목록
  • 메모보기
  • 메모삭제 확인

왜 이런 구조가 나올까? 고민을 하며 다음 글로ㅎㅎ;

색상을 바꿔요

눈에 편한 색상을 골라보세요 :)

Darkreader 플러그인으로 선택한 색상이 제대로 표시되지 않을 수 있습니다.