MVC에서 모델은 유효성 검사를 처리해야합니까?


25

MVC 패턴을 사용하기 위해 개발 한 웹 응용 프로그램을 다시 작성하려고하는데 모델에서 유효성 검사를 처리해야하는지 잘 모르겠습니다. 예를 들어, 다음과 같이 내 모델 중 하나를 설정하고 있습니다.

class AM_Products extends AM_Object 
{
    public function save( $new_data = array() ) 
    {
        // Save code
    }
}

첫 번째 질문 : 내 저장 메소드가 $ new_data에서 유효성 검사 함수를 호출해야하는지 또는 데이터가 이미 유효성 검사를 받았다고 생각하는지 궁금합니다.

또한 유효성 검사를 제공하는 경우 데이터 형식을 정의하는 일부 모델 코드는 다음과 같습니다.

class AM_Products extends AM_Object
{
    protected function init() // Called by __construct in AM_Object
    {
        // This would match up to the database column `age`
        register_property( 'age', 'Age', array( 'type' => 'int', 'min' => 10, 'max' => 30 ) ); 
    }
}

두 번째 질문 : AM_Object의 모든 하위 클래스는 해당 특정 객체의 데이터베이스에있는 각 열에 대해 register_property를 실행합니다. 이것이 좋은 방법인지 잘 모르겠습니다.

세 번째 질문 : 모델에서 유효성 검사를 처리해야하는 경우 오류 메시지 또는 오류 코드를 반환하고 뷰에서 코드를 사용하여 적절한 메시지를 표시해야합니까?

답변:


30

첫 번째 답변 : 모델의 핵심 역할은 무결성을 유지하는 것입니다. 그러나 사용자 입력 처리는 컨트롤러의 책임입니다.

즉, 컨트롤러는 사용자 데이터 (대부분은 문자열 임)를 의미있는 것으로 변환해야합니다. 구문 분석이 필요합니다 (예 : 다른 소수 연산자 등이있는 경우 로캘과 같은 항목에 따라 달라질 수 있음).
따라서 "데이터가 제대로 구성되어 있습니까?"와 같이 실제 유효성 검사는 컨트롤러에서 수행해야합니다. 그러나 "데이터가 의미가 있는가?"와 같은 검증 모델 내에서 수행해야합니다.

예를 들어이를 명확하게하려면 :
응용 프로그램에서 날짜와 함께 일부 엔터티를 추가 할 수 있다고 가정합니다 ( 예 : 마감일 문제). 날짜가 단순한 Unix 타임 스탬프로 표시 될 수있는 API가있을 수 있지만 HTML 페이지에서 오는 경우 다른 값 세트 또는 MM / DD / YYYY 형식의 문자열이됩니다. 모델에서이 정보를 원하지 않습니다. 각 컨트롤러가 개별적으로 날짜를 파악하려고합니다. 그러나 날짜가 모델로 전달 될 때 모델은 무결성을 유지해야합니다. 예를 들어, 휴일 / 일요일 등의 과거 날짜 또는 날짜를 허용하지 않는 것이 좋습니다.

컨트롤러에는 입력 (처리) 규칙이 포함되어 있습니다. 모델에 비즈니스 규칙이 포함되어 있습니다. 어떤 일이 있어도 비즈니스 규칙을 항상 적용하기를 원합니다. 컨트롤러에 비즈니스 규칙이 있다고 가정하면 다른 컨트롤러를 만들어야하는 경우이를 복제해야합니다.

두 번째 답변 : 이 방법은 의미가 있지만 방법을 더욱 강력하게 만들 수 있습니다. 마지막 매개 변수는 배열 IContstraint이 아니라 다음과 같이 정의 된 인스턴스 여야합니다 .

interface IConstraint {
     function test($value);//returns bool
}

그리고 숫자의 경우 다음과 같은 것을 가질 수 있습니다.

class NumConstraint {
    var $grain;
    var $min;
    var $max;
    function __construct($grain = 1, $min = NULL, $max = NULL) {
         if ($min === NULL) $min = INT_MIN;
         if ($max === NULL) $max = INT_MAX;
         $this->min = $min;
         $this->max = $max;
         $this->grain = $grain;
    }
    function test($value) {
         return ($value % $this->grain == 0 && $value >= $min && $value <= $max);
    }
}

또한 나는 'Age'정직하게 표현 해야 할 것이 무엇인지 알지 못한다 . 실제 속성 이름입니까? 기본적으로 규칙이 있다고 가정하면 매개 변수는 함수의 끝으로 이동하여 선택 사항이 될 수 있습니다. 설정하지 않으면 DB 열 이름 의 to_camel_case 가 기본값이됩니다 .

따라서 예제 호출은 다음과 같습니다.

register_property('age', new NumConstraint(1, 10, 30));

인터페이스 사용의 요점은 갈수록 점점 더 많은 제약 조건을 추가 할 수 있으며 원하는만큼 복잡 할 수 있다는 것입니다. 문자열이 정규식과 일치합니다. 날짜가 7 일 이상이어야합니다. 등등.

세 번째 답변 : 모든 모델 엔터티에는 다음과 같은 방법이 있어야합니다 Result checkValue(string property, mixed value). 데이터 설정 하기 전에 컨트롤러가 호출해야 합니다. 는 Result검사가 실패했는지에 대한 모든 정보를 가지고 있고, 컨트롤러가 따라보기로 사람들을 전파 할 수 있도록했던 경우, 이유를 제시해야한다.
모델에 잘못된 값이 전달되면 모델은 예외를 발생시켜 응답해야합니다.


이 글을 보내 주셔서 감사합니다. MVC에 대해 많은 것을 분명히했습니다.
AmadeusDrZaius

5

"back2dos"에 전적으로 동의하지 않습니다. 권장 사항은 항상 별도의 양식 / 유효성 검사 계층을 사용하여 컨트롤러가 입력 데이터를 모델로 보내기 전에 유효성 검사에 사용할 수 있도록하는 것입니다.

이론적 관점에서 볼 때 모델 유효성 검사는 신뢰할 수있는 데이터 (내부 시스템 상태)에서 작동하며 언제라도 이상적으로 반복 할 수 있어야하며, 입력 유효성 검사는 신뢰할 수없는 출처에서 온 데이터 (사용 사례 및 사용자 권한에 따라)에서 한 번만 명시 적으로 작동해야합니다.

이러한 분리를 통해 의존성 주입을 통해 느슨하게 결합 할 수있는 재사용 가능한 모델, 컨트롤러 및 양식을 작성할 수 있습니다. 입력 검증은 화이트리스트 검증 ( "알려진 것으로 인정")으로, 모델 검증은 블랙리스트 검증 ( "알려진 것으로 거부")으로 생각하십시오. 화이트리스트 유효성 검사는보다 안전하지만 블랙리스트 유효성 검사는 모델 계층이 특정 사용 사례로 지나치게 제한되는 것을 방지합니다.

유효하지 않은 모델 데이터는 항상 예외를 발생시켜야하며 (그렇지 않으면 응용 프로그램은 실수를 알리지 않고 계속 실행할 수 있습니다) 외부 소스에서 오는 유효하지 않은 입력 값은 예상치 못한 것이 아니라 일반적입니다 (실패하지 않은 사용자가없는 경우).

참조 : https://lastzero.net/2015/11/why-im-using-a-separate-layer-for-input-data-validation/


간단히하기 위해 Validator 클래스 패밀리가 있고 모든 검증이 전략화 된 계층 구조로 수행되었다고 가정합니다. 구체적인 유효성 검사기 어린이는 전자 메일, 전화 번호, 양식 토큰, 보안 문자, 암호 등의 특수 유효성 검사기로 구성 될 수도 있습니다. 컨트롤러 입력 유효성 검사는 1) 컨트롤러 및 방법 / 명령의 존재 확인 및 2) 데이터의 예비 검사 (예 : HTTP 요청 방법, 데이터 입력 수 (너무 많거나 너무 적습니까?))의 두 가지 종류입니다.
Anthony Rutledge

입력 수를 확인한 후에는 HTML 양식의 모든 제어가 공백으로 남겨질 때 HTML 양식의 모든 제어가 무언가를 제출하지 않으므로 요청 당 입력 수는 다를 수 있음을 명심하여 이름으로 올바른 HTML 제어가 제출되었음을 알아야합니다 ( 특히 확인란). 그 후, 마지막 예비 점검은 입력 크기의 테스트입니다. 제 생각에는,이 있어야한다 초기 ,하지 말. 컨트롤러 유효성 검사기에서 수량, 제어 이름 및 기본 입력 크기 검사를 수행한다는 것은 컨트롤러의 각 명령 / 방법에 대한 유효성 검사기가 있다는 의미입니다. 이것이 귀하의 응용 프로그램을보다 안전하게 만든다고 생각합니다.
Anthony Rutledge

예, 명령 의 컨트롤러 유효성 검사기모델 메서드에 필요한 인수 (있는 경우)와 밀접하게 연결 되지만 컨트롤러 자체는 해당 컨트롤러 유효성 검사기 에 대한 참조를 위해 저장되지 않습니다 . 대부분의 입력이 합법적이라는 가정하에 진행해서는 안되므로 이는 가치있는 타협입니다. 애플리케이션에 대한 불법적 인 액세스를 빨리 중지할수록 좋습니다. 컨트롤러 유효성 검사기 클래스 (수량, 이름 및 최대 입력 크기)에서이를 수행하면 악의적 인 HTTP 요청을 명확하게 거부하기 위해 전체 모델을 인스턴스화하지 않아도됩니다.
Anthony Rutledge

즉, 최대 입력 크기 문제를 해결하기 전에 인코딩이 올바른지 확인해야합니다. 모든 것을 고려하면, 작업이 캡슐화되어 있어도 모델이 수행하기에는 너무 많은 것입니다. 악성 요청을 거부하는 데 불필요하게 비싸게됩니다. 요약하면, 컨트롤러는 모델로 보내는 것에 대해 더 많은 책임을 져야합니다. 제어기 레벨 실패는 치명적이어야하며, 200 OK 이외의 요청자에게 리턴 정보가 없어야합니다. 활동을 기록하십시오. 치명적인 예외를 던지십시오. 모든 활동을 종료하십시오. 가능한 빨리 모든 프로세스를 중지하십시오.
Anthony Rutledge

최소 컨트롤, 최대 컨트롤, 올바른 컨트롤, 입력 인코딩 및 최대 입력 크기는 모두 요청의 특성과 관련이 있습니다 (어느 방식이든 상관 없음). 일부 사람들은이 다섯 가지 핵심 사항을 요청의 존중 여부를 결정하는 것으로 식별하지 않았습니다. 이 모든 것이 만족되지 않으면 왜이 정보를 모델로 전송합니까? 좋은 질문.
Anthony Rutledge

3

예, 모델은 유효성 검사를 수행해야합니다. UI도 입력의 유효성을 검사해야합니다.

유효한 값과 상태를 결정하는 것은 모델의 책임입니다. 때때로 그러한 규칙은 자주 바뀝니다. 이 경우 메타 데이터에서 모델을 피드하거나 장식합니다.


사용자의 의도가 명백하게 악의적이거나 오류 인 경우는 어떻습니까? 예를 들어 특정 HTTP 요청에는 입력 값이 7 개를 넘지 않아야하지만 컨트롤러는 70을 얻습니다. 요청이 명확하게 손상되었을 때 모델에 도달 할 수있는 허용 된 값 수의 10 배 (10 배)를 실제로 허용 하시겠습니까? 이 경우 특정 요청의 상태가 아니라 문제가되는 전체 요청의 상태입니다. 심층 방어 전략은 데이터를 모델로 전송하기 전에 HTTP 요청의 특성을 검사해야한다고 제안합니다.
Anthony Rutledge

(계속)이 방법으로 특정 사용자 제공 값 및 상태가 유효한지 확인하지 않고 요청의 전체가 유효한지 확인합니다. 아직까지 드릴 다운 할 필요는 없습니다. 기름은 이미 표면에 있습니다.
Anthony Rutledge

(계속) 프런트 엔드 유효성 검사를 강제 할 방법이 없습니다. 자동화 된 도구를 웹 응용 프로그램과 인터페이스로 사용할 수 있다는 것을 고려해야합니다.
Anthony Rutledge

(사고 후) 모델의 유효한 값과 데이터 상태가 중요하지만 컨트롤러를 통해 들어오는 요청 의 의도부딪쳤다 . 의도 확인을 생략하면 응용 프로그램이 더 취약 해집니다. 의도는 좋거나 (규칙에 따라 연주) 나쁘게 (규칙 밖에 나가기) 수 있습니다. 입력에 대한 기본 점검 (최소 제어, 최대 제어, 올바른 제어, 입력 인코딩 및 최대 입력 크기)을 통해 의도 를 확인할 수 있습니다. 그것은 전부 또는 아무것도 아닌 제안입니다. 모든 것이 통과되거나 요청이 유효하지 않습니다. 모델에 아무것도 보낼 필요가 없습니다.
Anthony Rutledge

2

좋은 질문입니다!

월드 와이드 웹 개발과 관련하여 다음을 요청하면 어떻게 될까요?

"사용자 인터페이스에서 잘못된 사용자 입력이 컨트롤러에 제공되는 경우 컨트롤러 는 일종의 주기적 루프로 View를 업데이트하여 명령 및 입력 데이터를 처리하기 전에 정확하게해야 합니까? 어떻게? 뷰는 정상 상태에서 어떻게 업데이트됩니까? 뷰는 모델과 밀접하게 연결되어 있습니까? 사용자 입력 유효성 검사 는 모델의 핵심 비즈니스 논리 입니까 , 아니면 모델에 대한 예비 작업 입니까? 따라서 컨트롤러 내부에서 발생해야합니다 (사용자 입력 데이터가 요청의 일부이기 때문에)?

(실제로 좋은 입력을 얻을 때까지 모델을 인스턴스화하는 데 지연이 발생할 수 있습니까?)

내 의견은 모델이 모델 인스턴스화 이전 (그리고 모델이 입력 데이터를 가져 오기 전에) 발생 해야하는 기본 HTTP 요청 입력 유효성 검사에 의해 방해받지 않고 순수하고 깨끗한 환경을 가능한 한 많이 관리해야한다는 의견입니다 . 상태 데이터 (영구적 또는 다른 방식) 및 API 관계 관리가 모델의 세계이므로 컨트롤러에서 기본 HTTP 요청 입력 유효성 검사가 발생하도록합니다.

요약.

1) 컨트롤러와 메소드가 존재해야 다른 경로를 진행할 수 있으므로 경로를 URL에서 구문 분석하십시오. 이는 진정한 컨트롤러에 도달하기 전에 프론트 컨트롤러 영역 (라우터 클래스)에서 반드시 발생해야합니다. 어. :-)

2) 모델에는 HTTP 요청, 데이터베이스, 파일, API 및 네트워크와 같은 많은 입력 데이터 소스가있을 수 있습니다. 모든 입력 유효성 검증을 모델 에 배치하려는 경우 프로그램에 대한 비즈니스 요구 사항의 일부인 HTTP 요청 입력 유효성 검증 을 고려 하십시오. 경우 폐쇄.

3) 그러나 HTTP 요청 입력 이 좋지 않은 경우 많은 객체를 인스턴스화하는 비용을 겪는 것은 근시안적입니다 ! 모델과 모든 복잡성 (예, API 및 DB 입력 / 출력 데이터에 대한 더 많은 유효성 검사기)을 인스턴스화하기 전에 유효성을 검사 하여 ** HTTP 요청 입력 **이 좋은지 ( 요청과 함께 제공됨) 알 수 있습니다.

다음을 테스트하십시오.

a) HTTP 요청 방법 (GET, POST, PUT, PATCH, DELETE ...)

b) 최소 HTML 컨트롤 (충분한 것이 있습니까?)

c) 최대 HTML 컨트롤 (너무 많습니까?).

d) 올바른 HTML 컨트롤 (올바른 컨트롤이 있습니까?)

e) 입력 인코딩 (일반적으로 인코딩 UTF-8입니까?)

f) 최대 입력 크기 (입력이 범위를 벗어 났습니까?).

문자열과 파일을 얻을 수 있으므로 요청이 서버에 부딪히면 모델이 인스턴스화 될 때까지 기다리는 것이 매우 비쌀 수 있습니다.

여기에 설명 한 것은 컨트롤러를 통해 들어오는 요청 의 의도 에 부딪칩니다 . 의도 확인을 생략하면 응용 프로그램이 더 취약 해집니다. 의도 거나 ( 기본 규칙에 따라 재생) 나쁘게 (기본 규칙 외부로 나가기) 수 있습니다.

HTTP 요청의 의도전적으로 또는 전혀없는 제안입니다. 모든 것이 통과되거나 요청이 유효하지 않습니다 . 모델에 아무것도 보낼 필요가 없습니다.

이 기본 HTTP 요청 의도 수준은 일반 사용자 입력 오류 및 유효성 검사와 관련없습니다 . 내 응용 프로그램에서 HTTP 요청은 위의 다섯 가지 방법으로 유효해야합니다. A의 심층 경우 말하기의 방법, 당신은 서버 측에서 사용자 입력 유효성 검사에 결코 어떤 이 다섯 가지가 실패합니다.

그렇습니다. 파일 입력조차도 프런트 엔드의 시도와 일치해야 사용자에게 허용되는 최대 파일 크기를 확인하고 알려줍니다. HTML 만? JavaScript가 없습니까? 그러나 사용자는 너무 큰 파일을 업로드 한 결과 (주로 모든 양식 데이터가 손실되고 시스템에서 쫓겨날 수 있음)에 대해 알려야합니다.

4) 이것은 HTTP 요청 입력 데이터 가 애플리케이션의 비즈니스 로직의 일부가 아님을 의미합니까 ? 아니요, 컴퓨터가 유한 한 장치이므로 리소스를 현명하게 사용해야한다는 의미입니다. 나중에 악의적 인 활동을 더 빨리 중지하는 것이 좋습니다. 나중에 중지하기 위해 더 많은 컴퓨팅 리소스를 지불해야합니다.

5) HTTP 요청 입력 이 잘못된 경우 전체 요청이 잘못되었습니다 . 그것이 내가 보는 방법입니다. 올바른 HTTP 요청 입력의 정의는 모델의 비즈니스 요구 사항에서 파생되지만 자원 구분 지점이 있어야합니다. 잘못된 요청을 종료하고 "오, 이봐, 신경 쓰지 마. 나쁜 요청."

사용자가 합리적인 입력 실수를 저지른 것이 아니라 HTTP 요청이 범위를 벗어난 것으로 판단하여 악의적 인 것으로 선언하고 즉시 중지해야합니다.

6) 따라서 돈 때문에 HTTP 요청 (METHOD, URL / route 및 데이터)이 모두 좋거나 다른 방법으로 진행할 수 있습니다. 강력한 모델에는 이미 검증 작업이 필요하지만, 좋은 자원 목자는 "나의 길 또는 높은 길입니다. 올바르거나 오지 마십시오"라고 말합니다.

그러나 그것은 당신의 프로그램입니다. "한 가지 이상의 방법이 있습니다." 어떤 방법은 다른 방법보다 시간과 비용이 많이 듭니다. 나중에 (모델에서) HTTP 요청 데이터의 유효성을 검사하면 응용 프로그램 수명 기간 동안 (특히 확장 또는 축소되는 경우) 비용이 더 많이 듭니다.

유효성 검사기가 모듈 식인 경우 컨트롤러에서 기본 * HTTP 요청 입력 ** 유효성을 검사해도 문제가되지 않습니다. 전략화 된 Validator 클래스 만 사용하십시오. 유효성 검사기는 때로는 특수 유효성 검사기 (이메일, 전화, 양식 토큰, 보안 문자 등)로 구성되기도합니다.

어떤 사람들은 이것이 완전히 잘못된 것으로보고 있지만, Gang of Four가 Design Patterns : Reusable Object-Oriented Software의 요소를 작성할 때 초기 단계에있었습니다 .

===================================================== =========================

이제는 정상적인 사용자 입력 유효성 검사 (HTTP 요청이 유효한 것으로 간주 된 후)와 관련되어 있으므로 사용자가 생각해야 할 내용이 엉망이되면보기를 업데이트하고 있습니다! 이러한 종류의 사용자 입력 유효성 검사는 모델에서 발생해야합니다.

프론트 엔드에서 JavaScript를 보증하지 않습니다. 즉, 오류 상태로 응용 프로그램 UI를 비동기식으로 업데이트 할 수있는 방법이 없습니다. 진정한 점진적 향상은 동기 사용 사례에도 적용됩니다.

동기 사용 사례에 대한 회계는 일부 사람들이 모든 UI 트릭 (상태 표시 / 숨기기 제어, 사용 안함 / 사용 제어)의 상태를 추적하는 데 시간이 걸리고 번거롭기 때문에 점점 더 많이 잃어 버리는 기술입니다. , 오류 표시, 오류 메시지) (일반적으로 배열 상태 추적)

업데이트 : 다이어그램에서을 View참조해야 한다고 말합니다 Model. 아니요 . 느슨한 결합을 유지 View하려면 데이터를 보낸 사람에게 전달해야합니다 Model. 여기에 이미지 설명을 입력하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.