MVC에서 모델을 어떻게 구성해야합니까? [닫은]


551

MVC 프레임 워크를 파악하고 모델에 얼마나 많은 코드가 들어가야하는지 종종 궁금합니다. 나는 다음과 같은 메소드를 가진 데이터 액세스 클래스를 사용하는 경향이 있습니다.

public function CheckUsername($connection, $username)
{
    try
    {
        $data = array();
        $data['Username'] = $username;

        //// SQL
        $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";

        //// Execute statement
        return $this->ExecuteObject($connection, $sql, $data);
    }
    catch(Exception $e)
    {
        throw $e;
    }
}

내 모델은 데이터베이스 테이블에 매핑되는 엔터티 클래스 인 경향이 있습니다.

모델 객체에 위의 코드뿐만 아니라 모든 데이터베이스 매핑 속성이 있어야합니까, 아니면 실제로 데이터베이스가 작동하는 코드를 분리해도 괜찮습니까?

결국 네 개의 레이어가 있습니까?


133
왜 다시 예외를 던지기 위해 예외를 잡는가?
Bailey Parker

9
@Elias Van Ootegem : 요점을 놓쳤습니다. 이 경우 그들을 잡는 것은 의미가 없습니다.
Karoly Horvath

4
@Elias Van Ootegem : 응? 다시 던지기와 함께 작동하면 상위 레이어가 예외를 포착한다는 의미입니다. 그러나 하나가 있다면, 그것은 무의미한 다시 던지지 않고 그것을 잡을 것입니다 ... (여전히 얻지 못하면 작은 테스트 코드를 조롱하십시오)
Karoly Horvath

3
@Elias Van Ootegem : 특정 계층에서 예외를 처리하지 않는다고해서 앱이 중단된다는 의미는 아닙니다. 다시 던질 필요가있는 코드 예제를 구성하십시오 (보다 정확하게 : 구성하지 못함). 하자,이 논외 대화를 중지 하십시오
카 롤리 바스

6
@ drrcknlsn : 그것은 유효한 인수이지만,이 경우 적어도 예상되는 예외를 포착하면 generic Exception에는 많은 문서 값이 없습니다. 개인적으로 그 길을 따라 가면 PHPDoc @exception또는 유사한 메커니즘을 선택하므로 생성 된 문서에 표시됩니다.
Karoly Horvath

답변:


903

면책 조항 : 다음은 PHP 기반 웹 응용 프로그램의 맥락에서 MVC와 같은 패턴을 이해하는 방법에 대한 설명입니다. 내용에 사용 된 모든 외부 링크는 용어와 개념을 설명하기 위해 있으며 주제에 대한 내 자신의 신뢰성을 암시 하지 않습니다 .

가장 먼저 정리해야 할 것은 모델은 레이어 입니다.

둘째 : 클래식 MVC 와 웹 개발에 사용하는 것에는 차이 가 있습니다. 여기에 내가 쓴 오래된 답변이 있는데, 어떻게 다른지 간단히 설명합니다.

모델이 아닌 것 :

모델은 클래스 또는 단일 객체가 아닙니다. 대부분의 프레임 워크가 이러한 오해를 영속시키기 때문에 (나도 그렇게 배우기 시작했을 때 원래의 대답이 쓰여졌지만) 그렇게 하는 것은 매우 일반적인 실수 입니다.

ORM (Object-Relational Mapping) 기술이나 데이터베이스 테이블의 추상화도 아닙니다. 달리 말하면 누구나 다른 새로운 ORM 또는 전체 프레임 워크 를 '판매' 하려고 할 것 입니다.

모델이란?

적절한 MVC 적응에서 M은 모든 도메인 비즈니스 로직을 포함하며 모델 계층주로 세 가지 유형의 구조로 구성됩니다.

  • 도메인 객체

    도메인 객체는 순수한 도메인 정보의 논리적 컨테이너입니다. 일반적으로 문제점 도메인 공간의 논리 엔티티를 나타냅니다. 일반적으로 비즈니스 로직 이라고합니다 .

    여기에서 송장을 보내기 전에 데이터의 유효성을 검사하거나 주문의 총 비용을 계산하는 방법을 정의 할 수 있습니다. 동시에, 도메인 객체가 저장 전혀 모르고있다 -도에서 경우 (SQL 데이터베이스, REST API를, 텍스트 파일 등)도 심지어는 경우 가 저장하거나 검색하세요.

  • 데이터 매퍼

    이러한 객체는 스토리지에만 책임이 있습니다. 데이터베이스에 정보를 저장하면 SQL이있는 곳이됩니다. 또는 XML 파일을 사용하여 데이터를 저장하고 데이터 매퍼 가 XML 파일에서 구문 분석하고 있습니다.

  • 서비스

    이를 "상위 레벨 도메인 오브젝트"로 생각할 수 있지만 비즈니스 로직 대신 서비스도메인 오브젝트맵퍼 간의 상호 작용을 담당합니다 . 이러한 구조는 결국 도메인 비즈니스 로직과 상호 작용하기위한 "공용"인터페이스를 작성합니다. 이를 피할 수는 있지만 일부 도메인 로직을 컨트롤러 로 유출하는 경우가 있습니다 .

    ACL 구현 질문 에이 주제에 대한 관련 답변이 있습니다. 유용 할 수 있습니다.

모델 계층과 MVC 트라이어드의 다른 부분 간의 통신은 서비스를 통해서만 이루어져야 합니다 . 명확한 분리는 몇 가지 추가 이점이 있습니다.

  • 단일 책임 원칙 (SRP) 을 시행하는 데 도움이됩니다.
  • 논리가 변경되는 경우 추가 '흔들기 방'제공
  • 컨트롤러를 최대한 간단하게 유지
  • 외부 API가 필요한 경우 명확한 청사진을 제공합니다.

 

모델과 상호 작용하는 방법?

전제 조건 : "글로벌 스테이트 및 싱글 톤""사물을 찾지 마십시오!" 강의 시청 클린 코드 대화에서.

서비스 인스턴스에 대한 액세스 권한 얻기

이러한 서비스에 액세스하기 위해 ViewController 인스턴스 ( "UI 계층"이라고 부름)에 대해 두 가지 일반적인 접근 방식이 있습니다.

  1. DI 컨테이너를 사용하여 뷰 및 컨트롤러의 생성자에 필요한 서비스를 직접 삽입 할 수 있습니다.
  2. 모든 뷰 및 컨트롤러에 대한 필수 종속성으로 서비스 팩토리를 사용합니다.

의심 할 수 있듯이 DI 컨테이너는 훨씬 더 우아한 솔루션입니다 (초보자에게는 가장 쉬운 방법은 아님). 이 기능을 고려할 것을 권장하는 두 라이브러리는 Syfmony의 독립형 DependencyInjection 구성 요소 또는 Auryn 입니다.

팩토리 및 DI 컨테이너를 사용하는 솔루션을 사용하면 선택한 컨트롤러간에 다양한 서버 인스턴스를 공유하고 지정된 요청-응답주기 동안 볼 수 있습니다.

모델 상태의 변경

이제 컨트롤러에서 모델 레이어에 액세스 할 수 있으므로 실제로 사용하기 시작해야합니다.

public function postLogin(Request $request)
{
    $email = $request->get('email');
    $identity = $this->identification->findIdentityByEmailAddress($email);
    $this->identification->loginWithPassword(
        $identity,
        $request->get('password')
    );
}

컨트롤러는 매우 명확한 작업을 수행합니다. 사용자 입력을 취하고이 입력을 기반으로 비즈니스 로직의 현재 상태를 변경합니다. 이 예에서 사이에 변경된 상태는 "익명 사용자"및 "로그인 한 사용자"입니다.

Controller는 사용자 입력의 유효성을 검사 할 책임이 없습니다. 비즈니스 규칙의 일부이고 Controller가 여기 또는 여기에서 볼 수있는 것과 같은 SQL 쿼리를 호출 하지 않기 때문입니다.

사용자에게 상태 변경을 표시합니다.

사용자가 로그인했거나 실패했습니다. 이제 뭐? 상기 사용자는 여전히 그것을 알지 못한다. 따라서 실제로 응답을 생성해야하며 이는 뷰의 책임입니다.

public function postLogin()
{
    $path = '/login';
    if ($this->identification->isUserLoggedIn()) {
        $path = '/dashboard';
    }
    return new RedirectResponse($path); 
}

이 경우 뷰는 현재 모델 계층 상태에 따라 두 가지 가능한 응답 중 하나를 생성했습니다. 다른 유스 케이스의 경우 "현재 선택된 기사"와 같은 것을 기반으로 렌더링 할 다른 템플리트를 선택하는보기가 있습니다.

프리젠 테이션 레이어는 실제로 PHP에서 MVC보기 이해에 설명 된대로 상당히 정교해질 수 있습니다 .

그러나 나는 단지 REST API를 만들고 있습니다!

물론 이것이 과잉 상태 인 상황이 있습니다.

MVC는 우려 분리 원칙 에 대한 구체적인 솔루션 일뿐 입니다. MVC는 비즈니스 로직과 사용자 인터페이스를 분리하고 UI에서는 사용자 입력과 프리젠 테이션 처리를 분리했습니다. 이것은 중요합니다. 사람들은 종종 그것을 "세가지"라고 묘사하지만 실제로는 세 개의 독립적 인 부분으로 구성되지는 않습니다. 구조는 다음과 같습니다.

MVC 분리

즉, 프리젠 테이션 레이어의 논리가 존재하지 않는 것에 가깝다면 실용적인 접근 방식은이를 단일 레이어로 유지하는 것입니다. 또한 모델 계층의 일부 측면을 상당히 단순화 할 수 있습니다.

이 방법을 사용하면 로그인 예제 (API 용)를 다음과 같이 작성할 수 있습니다.

public function postLogin(Request $request)
{
    $email = $request->get('email');
    $data = [
        'status' => 'ok',
    ];
    try {
        $identity = $this->identification->findIdentityByEmailAddress($email);
        $token = $this->identification->loginWithPassword(
            $identity,
            $request->get('password')
        );
    } catch (FailedIdentification $exception) {
        $data = [
            'status' => 'error',
            'message' => 'Login failed!',
        ]
    }

    return new JsonResponse($data);
}

이것이 지속 가능하지는 않지만 응답 본문을 렌더링하기위한 복잡한 논리가있는 경우이 단순화는보다 사소한 시나리오에 매우 유용합니다. 그러나 경고 복잡한 프리젠 테이션 로직 큰 코드베이스에서 사용하려고 할 때이 방법은, 악몽이 될 것이다.

 

모델을 구축하는 방법?

위에서 설명한 것처럼 단일 "Model"클래스가 없기 때문에 실제로 "모델을 빌드하지"마십시오. 대신 특정 방법을 수행 할 수있는 서비스 만들기부터 시작하십시오 . 그런 다음 Domain Objects and Mappers 를 구현 합니다.

서비스 방법의 예 :

위의 두 가지 접근 방식 모두에서 식별 서비스에 대한이 로그인 방법이있었습니다. 실제로 어떤 모습일까요? 내가 쓴 라이브러리 에서 동일한 기능의 약간 수정 된 버전을 사용하고 있습니다 .

public function loginWithPassword(Identity $identity, string $password): string
{
    if ($identity->matchPassword($password) === false) {
        $this->logWrongPasswordNotice($identity, [
            'email' => $identity->getEmailAddress(),
            'key' => $password, // this is the wrong password
        ]);

        throw new PasswordMismatch;
    }

    $identity->setPassword($password);
    $this->updateIdentityOnUse($identity);
    $cookie = $this->createCookieIdentity($identity);

    $this->logger->info('login successful', [
        'input' => [
            'email' => $identity->getEmailAddress(),
        ],
        'user' => [
            'account' => $identity->getAccountId(),
            'identity' => $identity->getId(),
        ],
    ]);

    return $cookie->getToken();
}

보시다시피,이 추상화 수준에서는 데이터가 어디서 가져 왔는지에 대한 표시가 없습니다. 데이터베이스 일 수도 있지만 테스트 목적으로 모의 객체 일 수도 있습니다. 실제로 사용되는 데이터 맵퍼조차도이 private서비스 의 방법에 숨겨져 있습니다 .

private function changeIdentityStatus(Entity\Identity $identity, int $status)
{
    $identity->setStatus($status);
    $identity->setLastUsed(time());
    $mapper = $this->mapperFactory->create(Mapper\Identity::class);
    $mapper->store($identity);
}

매퍼를 만드는 방법

지속성의 추상화를 구현하기 위해 가장 유연한 접근 방식은 사용자 정의 데이터 맵퍼 를 작성하는 것 입니다.

매퍼 다이어그램

부터 : PoEAA book

실제로는 특정 클래스 또는 수퍼 클래스와의 상호 작용을 위해 구현됩니다. 당신이 말할 수 있습니다 CustomerAdmin코드에서 (모두에서 상속 User슈퍼 클래스). 둘 다 서로 다른 필드를 포함하기 때문에 아마도 별도의 일치하는 매퍼를 갖게 될 것입니다. 그러나 공유되고 일반적으로 사용되는 작업으로 끝납니다. 예 : "마지막 온라인" 시간 업데이트 기존 매퍼를보다 복잡하게 만드는 대신보다 실용적인 접근 방식은 일반적인 "사용자 매퍼"를 사용하여 해당 타임 스탬프 만 업데이트하는 것입니다.

추가 의견 :

  1. 데이터베이스 테이블 및 모델

    데이터베이스 테이블, Domain ObjectMapper 간에 직접적인 1 : 1 : 1 관계가있는 경우가 많지만 대규모 프로젝트에서는 예상보다 덜 일반적 일 수 있습니다.

    • 단일 도메인 개체 가 사용하는 정보 는 다른 테이블에서 매핑 될 수 있지만 개체 자체는 데이터베이스에 지속성이 없습니다.

      예 : 월간 보고서를 생성하는 경우 이것은 다른 테이블에서 정보를 수집하지만 MonthlyReport데이터베이스 에는 마법의 테이블 이 없습니다 .

    • 단일 매퍼 는 여러 테이블에 영향을 줄 수 있습니다.

      예 :User 객체의 데이터를 저장하는 경우이 도메인 객체 에는 다른 도메인 객체 ( Group인스턴스) 모음이 포함될 수 있습니다 . 당신이 그들을 변경하고 저장할 경우 User데이터 매퍼 갱신 및 / 또는 여러 테이블에서 항목을 삽입해야합니다.

    • 단일 도메인 개체의 데이터 는 둘 이상의 테이블에 저장됩니다.

      예 : 대규모 시스템 (생각 : 중간 규모의 소셜 네트워크)에서는 사용자 인증 데이터와 자주 액세스하는 데이터를 더 큰 콘텐츠 청크와 별도로 저장하는 것이 실용적 일 수 있습니다. 이 경우 여전히 단일 User클래스 가있을 수 있지만 포함 된 정보는 전체 세부 사항을 가져 왔는지 여부에 따라 다릅니다.

    • 모든 도메인 개체에 대해 둘 이상의 매퍼가있을 수 있습니다

      예 : 공용 소프트웨어와 관리 소프트웨어를위한 공유 코드 기반 뉴스 사이트가 있습니다. 그러나 두 인터페이스 모두 동일한 Article클래스를 사용하지만 관리에는 더 많은 정보가 필요합니다. 이 경우 "내부"와 "외부"의 두 가지 별도 맵퍼가 있습니다. 각각 다른 쿼리를 수행하거나 심지어 다른 데이터베이스를 사용합니다 (마스터 또는 슬레이브에서와 같이).

  2. 보기는 템플릿이 아닙니다

    MVC의 인스턴스 보기 (패턴의 MVP 변형을 사용하지 않는 경우)는 프리젠 테이션 논리를 담당합니다. 즉, 각 보기 는 일반적으로 최소한 몇 개의 템플릿을 저글링합니다. 모델 레이어 에서 데이터를 획득 한 다음 수신 된 정보를 기반으로 템플릿을 선택하고 값을 설정합니다.

    이로부터 얻을 수있는 이점 중 하나는 재사용 성입니다. 당신이 만드는 경우 ListView잘 작성된 코드를 다음 클래스를, 당신은 동일한 클래스 나눠에게 사용자 목록과 기사 아래 댓글 프리젠 테이션을 할 수 있습니다. 둘 다 동일한 프리젠 테이션 로직을 가지고 있기 때문입니다. 템플릿 만 전환하면됩니다.

    네이티브 PHP 템플릿을 사용하거나 타사 템플릿 엔진을 사용할 수 있습니다 . View 인스턴스 를 완전히 대체 할 수있는 타사 라이브러리도있을 수 있습니다 .

  3. 이전 버전의 답변은 어떻습니까?

    유일한 주요 변경 사항은 이전 버전에서 Model 이라는 모델 이 실제로 서비스라는 것 입니다. "라이브러리 비유"의 나머지 부분은 꽤 잘 유지됩니다.

    내가 볼 수있는 유일한 결함은 이것이 도서관에서 당신에게 정보를 반환 할 것이기 때문에 실제로 이상한 도서관 일 것입니다. 그렇지 않으면 추상화 자체가 "누설"시작하기 때문에 책 자체를 만지지 마십시오. 더 적합한 유추를 생각해야 할 수도 있습니다.

  4. ViewController 인스턴스 의 관계는 무엇입니까 ?

    MVC 구조는 ui와 model의 두 계층으로 구성됩니다. UI 계층 의 주요 구조 는 뷰와 컨트롤러입니다.

    MVC 디자인 패턴을 사용하는 웹 사이트를 처리 할 때 가장 좋은 방법은 뷰와 컨트롤러간에 1 : 1 관계를 유지하는 것입니다. 각보기는 웹 사이트의 전체 페이지를 나타내며 해당 특정보기에 대한 모든 수신 요청을 처리하는 전용 컨트롤러가 있습니다.

    예를 들어, 열린 기사를 나타내려면 \Application\Controller\Document및 이 있어야 \Application\View\Document합니다. 여기에는 기사를 처리 할 때 UI 계층의 모든 주요 기능이 포함됩니다 (물론 기사와 직접 관련이없는 일부 XHR 구성 요소가 있을 수 있음 ) .


4
@Rinzler, 당신은 그 링크의 어느 곳에서도 Model에 대해 언급 한 것을 알 수 없습니다 (한 의견 제외). "데이터베이스 테이블에 대한 객체 지향 인터페이스" 뿐입니다 . 이것을 모델과 같은 것으로 성형하려고하면 SRPLSP를 위반하게 됩니다.
tereško 2016 년

8
@hafichuk은 ActiveRecord 패턴 을 사용하는 것이 합리적 일 때만 프로토 타이핑 하는 상황에만 해당됩니다 . 프로덕션에 적합한 코드를 작성하기 시작하면 코드는 스토리지와 비즈니스 로직을 혼합하기 때문에 안티 패턴이됩니다. 그리고 이후 모델 레이어는 다른 MVC 부품을 완전히 인식하지 못합니다. 원래 패턴의 변형에 따라 변경되지 않습니다 . MVVM을 사용하는 경우에도 마찬가지입니다. "복수 모델"이 없으며 아무 것도 매핑되지 않습니다. 모델은 레이어입니다.
tereško

3
짧은 버전-모델은 데이터 구조 입니다.
Eddie B

9
그가 MVC를 발명 한 것은 기사에 약간의 장점이있을 수 있습니다.
Eddie B

3
... 또는 심지어 일련의 기능. MVC는 대부분 OOP 방식으로 구현할 필요는 없지만 대부분 그렇게 구현됩니다. 가장 중요한 것은 레이어를 분리하고 올바른 데이터 및 제어 흐름을 설정하는 것입니다.
hek2mgl

37

비즈니스 로직 인 모든 것은 데이터베이스 쿼리, 계산, REST 호출 등 모델에 속합니다.

모델 자체에서 데이터 액세스 권한을 가질 수 있지만 MVC 패턴은이를 수행하는 것을 제한하지 않습니다. 서비스, ​​매퍼 등으로 설탕 코팅을 할 수 있지만 모델의 실제 정의는 비즈니스 로직을 처리하는 계층입니다. 클래스, 함수 또는 원하는 경우 gazillion 객체가있는 완전한 모듈 일 수 있습니다.

모델에서 직접 데이터베이스 쿼리를 실행하는 대신 실제로 데이터베이스 쿼리를 실행하는 별도의 개체를 보유하는 것이 항상 더 쉽습니다. 이는 모델에 모의 데이터베이스 종속성을 주입하기가 쉽기 때문에 단위 테스트시 특히 유용합니다.

class Database {
   protected $_conn;

   public function __construct($connection) {
       $this->_conn = $connection;
   }

   public function ExecuteObject($sql, $data) {
       // stuff
   }
}

abstract class Model {
   protected $_db;

   public function __construct(Database $db) {
       $this->_db = $db;
   }
}

class User extends Model {
   public function CheckUsername($username) {
       // ...
       $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
       return $this->_db->ExecuteObject($sql, $data);
   }
}

$db = new Database($conn);
$model = new User($db);
$model->CheckUsername('foo');

또한 PHP에서는 백 트레이스가 유지되므로 특히 예제와 같은 경우 예외를 잡거나 다시 던질 필요가 거의 없습니다. 예외를 처리하고 대신 컨트롤러에서 예외를 포착하십시오.


내 구조는 매우 비슷합니다. 조금 더 분리 한 것 같습니다. 연결을 통과하는 이유는 트랜잭션에서 청크를 실행해야했기 때문입니다. 사용자를 추가 한 다음 사용자를 역할에 추가하려고했지만 실패한 경우 다시 역할을 수행했습니다. 내가 그것을 분류 할 수있는 유일한 방법은 연결을 전달하는 것입니다.
Dietpixel

10
-1 : 또한 완전히 잘못되었습니다. 모델은 테이블에 대한 추상화가 아닙니다.
tereško

1
User클래스는 기본적으로 모델을 확장하지만, 객체를 itsn't. 사용자는 객체 여야하며 다음과 같은 속성을 갖습니다. id, name ... User클래스를 배포 하는 것이 도우미입니다.
TomSawyer

1
MVC는 이해하지만 OOP가 무엇인지 이해하지 못하는 것 같습니다. 이 시나리오에서 내가 말했듯 User이 객체를 나타내며와 같은 메소드가 아닌 사용자의 속성을 CheckUsername가져야합니다. 새 User객체 를 만들려면 어떻게해야 합니까? new User($db)
TomSawyer

@TomSawyer OOP는 객체에 속성이 필요하다는 것을 의미하지는 않습니다. 당신이 묘사하는 것은 디자인 패턴이며, 질문이나 질문에 대한 답과 관련이 없습니다. OOP는 언어 패턴이며 디자인 패턴이 아닙니다.
netcoder

20

웹 "MVC"에서는 원하는대로 할 수 있습니다.

원래 개념 (1) 은 모델을 비즈니스 로직으로 설명했습니다. 응용 프로그램 상태를 나타내며 일부 데이터 일관성을 강화해야합니다. 이러한 접근 방식은 종종 "뚱뚱한 모델"로 설명됩니다.

대부분의 PHP 프레임 워크는 모델이 단지 데이터베이스 인터페이스 인보다 얕은 접근 방식을 따릅니다. 그러나 최소한 이러한 모델은 여전히 ​​들어오는 데이터와 관계를 확인해야합니다.

어느 쪽이든 SQL 항목 또는 데이터베이스 호출을 다른 계층으로 분리하면 크게 멀지 않습니다. 이 방법으로 실제 스토리지 API가 아닌 실제 데이터 / 행동에만 관심을 가지면됩니다. (하지만 과도하게 사용하는 것은 부당합니다. 예를 들어 사전 설계되지 않은 경우 데이터베이스 백엔드를 파일 저장소로 대체 ​​할 수 없습니다.)


8
링크가 유효하지 않습니다 (404)
Kyslik

1
이것은 WebArchive에서 작동합니다 : web.archive.org/web/20101229204648/https://stackoverflow.com/…
Tudor

6

더 oftenly 대부분의 응용 프로그램 데이터, 디스플레이, 처리 부분이있을 것이다 그리고 우리는 단지 문자의 모든 사람들을 넣어 M, V하고 C.

모델 ( M) -> 응용 프로그램의 상태를 유지하는 특성을 가지고 있으며, 그것에 대해 아무 것도 알지 해달라고 V하고 C.

View ( V) -> 응용 프로그램의 형식을 표시하며 다이제스트하는 방법 만 알고 있으며 신경 쓰지 않습니다 C.

컨트롤러 ( C) ---> 어플리케이션 처리부를 가지며, M 및 V 사이의 배선으로 작용하고 양에 따라 M, V달리 M하고 V.

모두 서로간에 관심의 분리가 있습니다. 향후에는 변경이나 개선 사항을 매우 쉽게 추가 할 수 있습니다.


0

제 경우에는 쿼리, 페치 등과 같은 모든 직접적인 데이터베이스 상호 작용을 처리하는 데이터베이스 클래스가 있습니다. 따라서 데이터베이스를 MySQL 에서 PostgreSQL 로 변경해야한다면 아무런 문제가 없습니다. 추가 레이어를 추가하면 유용 할 수 있습니다.

각 테이블에는 고유 한 클래스와 고유 한 메소드가있을 수 있지만 실제로 데이터를 가져 오려면 데이터베이스 클래스가이를 처리 할 수 ​​있습니다.

파일 Database.php

class Database {
    private static $connection;
    private static $current_query;
    ...

    public static function query($sql) {
        if (!self::$connection){
            self::open_connection();
        }
        self::$current_query = $sql;
        $result = mysql_query($sql,self::$connection);

        if (!$result){
            self::close_connection();
            // throw custom error
            // The query failed for some reason. here is query :: self::$current_query
            $error = new Error(2,"There is an Error in the query.\n<b>Query:</b>\n{$sql}\n");
            $error->handleError();
        }
        return $result;
    }
 ....

    public static function find_by_sql($sql){
        if (!is_string($sql))
            return false;

        $result_set = self::query($sql);
        $obj_arr = array();
        while ($row = self::fetch_array($result_set))
        {
            $obj_arr[] = self::instantiate($row);
        }
        return $obj_arr;
    }
}

테이블 객체 classL

class DomainPeer extends Database {

    public static function getDomainInfoList() {
        $sql = 'SELECT ';
        $sql .='d.`id`,';
        $sql .='d.`name`,';
        $sql .='d.`shortName`,';
        $sql .='d.`created_at`,';
        $sql .='d.`updated_at`,';
        $sql .='count(q.id) as queries ';
        $sql .='FROM `domains` d ';
        $sql .='LEFT JOIN queries q on q.domainId = d.id ';
        $sql .='GROUP BY d.id';
        return self::find_by_sql($sql);
    }

    ....
}

이 예제가 좋은 구조를 만드는 데 도움이되기를 바랍니다.


12
"따라서 데이터베이스를 MySQL에서 PostgreSQL로 변경해야한다면 아무런 문제가 없을 것입니다." 위 코드를 사용하면 imo를 변경하는 데 큰 문제가 있습니다.
PeeHaa

편집 후, 시간이 지남에 따라 내 대답이 점점 더 의미가 없다는 것을 알았습니다. 그러나 여기에 머물러야합니다
Ibu

2
Database이 예에서는 클래스가 아닙니다. 함수의 래퍼 일뿐입니다. 또한 객체없이 어떻게 "테이블 객체 클래스"를 가질 수 있습니까?
tereško

2
@ tereško 나는 많은 게시물을 읽었으며 훌륭합니다. 그러나, 나는 어디에서나 공부할 완벽한 프레임 워크를 찾을 수 없습니다. "올바른 일"을 알고 있습니까? 아니면 적어도 당신이나 다른 사람들처럼 그것을 좋아하는 사람이 그렇게 말합니까? 감사.
johnny

늦었지만 PDO가 향후 변경을 용이하게하기 위해 DB '계층'을 만들어야하는 문제를 거의 해결한다는 점을 지적하고 싶습니다.
Matthew Goulart
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.