네트 스키마
스마트하고 이해하기 쉬운 API를 사용하여 주어진 스키마에 대한 데이터 구조의 검증 및 정규화를 위한 실용적인 라이브러리입니다.
문서는 웹사이트에서 찾을 수 있습니다.
설치:
composer require nette/schema
PHP 버전 8.1이 필요하며 최대 8.4까지 PHP를 지원합니다.
네테 스키마 앱이 마음에 드시나요? 새로운 기능을 기대하시나요?
감사합니다!
$schema
변수에는 유효성 검사 스키마가 있고(정확히 이것이 무엇을 의미하는지, 어떻게 만드는지는 나중에 설명하겠습니다) 변수 $data
에는 유효성을 검사하고 정규화하려는 데이터 구조가 있습니다. 예를 들어 API, 구성 파일 등을 통해 사용자가 보낸 데이터일 수 있습니다.
작업은 입력을 처리하고 정규화된 데이터를 반환하거나 오류 시 NetteSchemaValidationException 예외를 발생시키는 NetteSchemaProcessor 클래스에 의해 처리됩니다.
$ processor = new Nette Schema Processor ;
try {
$ normalized = $ processor -> process ( $ schema , $ data );
} catch ( Nette Schema ValidationException $ e ) {
echo ' Data is invalid: ' . $ e -> getMessage ();
}
$e->getMessages()
메소드는 모든 메시지 문자열의 배열을 반환하고 $e->getMessageObjects()
모든 메시지를 NetteSchemaMessage 개체로 반환합니다.
이제 스키마를 만들어 보겠습니다. NetteSchemaExpect 클래스는 이를 정의하는 데 사용되며 실제로 데이터가 어떻게 보일지에 대한 기대치를 정의합니다. 입력 데이터가 bool 유형의 processRefund
요소와 int 유형의 refundAmount
요소를 포함하는 구조(예: 배열)여야 한다고 가정해 보겠습니다.
use Nette Schema Expect ;
$ schema = Expect:: structure ([
' processRefund ' => Expect:: bool (),
' refundAmount ' => Expect:: int (),
]);
우리는 스키마 정의가 처음 보는 경우에도 명확해 보인다고 믿습니다.
검증을 위해 다음 데이터를 보내겠습니다.
$ data = [
' processRefund ' => true ,
' refundAmount ' => 17 ,
];
$ normalized = $ processor -> process ( $ schema , $ data ); // OK, it passes
출력, 즉 $normalized
값은 stdClass
객체입니다. 출력을 배열로 만들려면 Expect::structure([...])->castTo('array')
스키마에 캐스트를 추가합니다.
구조체의 모든 요소는 선택 사항이며 기본값은 null
입니다. 예:
$ data = [
' refundAmount ' => 17 ,
];
$ normalized = $ processor -> process ( $ schema , $ data ); // OK, it passes
// $normalized = {'processRefund' => null, 'refundAmount' => 17}
기본값이 null
이라는 사실이 입력 데이터 'processRefund' => null
에서 허용된다는 의미는 아닙니다. 아니요, 입력은 부울이어야 합니다. 즉, true
또는 false
만 가능합니다. Expect::bool()->nullable()
통해 명시적으로 null
허용해야 합니다.
Expect::bool()->required()
사용하여 항목을 필수로 설정할 수 있습니다. Expect::bool()->default(false)
또는 Expect::bool(false)
사용하여 기본값을 false
로 변경합니다.
부울 외에 1
과 0
허용하려면 어떻게 해야 할까요? 그런 다음 허용되는 값을 나열하고 부울로 정규화합니다.
$ schema = Expect:: structure ([
' processRefund ' => Expect:: anyOf ( true , false , 1 , 0 )-> castTo ( ' bool ' ),
' refundAmount ' => Expect:: int (),
]);
$ normalized = $ processor -> process ( $ schema , $ data );
is_bool ( $ normalized -> processRefund ); // true
이제 스키마가 정의되는 방식과 구조의 개별 요소가 작동하는 방식에 대한 기본 사항을 알았습니다. 이제 스키마 정의에 사용할 수 있는 다른 모든 요소가 무엇인지 살펴보겠습니다.
모든 표준 PHP 데이터 유형은 스키마에 나열될 수 있습니다.
Expect:: string ( $ default = null )
Expect:: int ( $ default = null )
Expect:: float ( $ default = null )
Expect:: bool ( $ default = null )
Expect::null()
Expect:: array ( $ default = [])
그런 다음 Expect::type('scalar')
또는 축약된 Expect::scalar()
통해 유효성 검사기가 지원하는 모든 유형입니다. 또한 클래스 또는 인터페이스 이름도 허용됩니다(예 Expect::type('AddressEntity')
.
통합 표기법을 사용할 수도 있습니다.
Expect:: type ( ' bool|string|array ' )
기본값은 빈 배열인 array
및 list
제외하고 항상 null
입니다. (리스트는 숫자 키를 0부터 오름차순으로 인덱싱한 배열, 즉 비연관 배열입니다.)
배열은 너무 일반적인 구조이므로 포함할 수 있는 요소를 정확하게 지정하는 것이 더 유용합니다. 예를 들어 요소가 문자열만 될 수 있는 배열은 다음과 같습니다.
$ schema = Expect:: arrayOf ( ' string ' );
$ processor -> process ( $ schema , [ ' hello ' , ' world ' ]); // OK
$ processor -> process ( $ schema , [ ' a ' => ' hello ' , ' b ' => ' world ' ]); // OK
$ processor -> process ( $ schema , [ ' key ' => 123 ]); // ERROR: 123 is not a string
두 번째 매개변수는 키를 지정하는 데 사용할 수 있습니다(버전 1.2부터):
$ schema = Expect:: arrayOf ( ' string ' , ' int ' );
$ processor -> process ( $ schema , [ ' hello ' , ' world ' ]); // OK
$ processor -> process ( $ schema , [ ' a ' => ' hello ' ]); // ERROR: 'a' is not int
목록은 인덱스 배열입니다.
$ schema = Expect:: listOf ( ' string ' );
$ processor -> process ( $ schema , [ ' a ' , ' b ' ]); // OK
$ processor -> process ( $ schema , [ ' a ' , 123 ]); // ERROR: 123 is not a string
$ processor -> process ( $ schema , [ ' key ' => ' a ' ]); // ERROR: is not a list
$ processor -> process ( $ schema , [ 1 => ' a ' , 0 => ' b ' ]); // ERROR: is not a list
매개변수는 스키마일 수도 있으므로 다음과 같이 작성할 수 있습니다.
Expect:: arrayOf (Expect:: bool ())
기본값은 빈 배열입니다. 기본값을 지정하고 mergeDefaults()
호출하면 전달된 데이터와 병합됩니다.
anyOf()
값이 될 수 있는 값 또는 스키마의 집합입니다. 'a'
, true
또는 null
일 수 있는 요소 배열을 작성하는 방법은 다음과 같습니다.
$ schema = Expect:: listOf (
Expect:: anyOf ( ' a ' , true , null ),
);
$ processor -> process ( $ schema , [ ' a ' , true , null , ' a ' ]); // OK
$ processor -> process ( $ schema , [ ' a ' , false ]); // ERROR: false does not belong there
열거형 요소는 스키마일 수도 있습니다.
$ schema = Expect:: listOf (
Expect:: anyOf (Expect:: string (), true , null ),
);
$ processor -> process ( $ schema , [ ' foo ' , true , null , ' bar ' ]); // OK
$ processor -> process ( $ schema , [ 123 ]); // ERROR
anyOf()
메서드는 변형을 배열이 아닌 개별 매개변수로 허용합니다. 값 배열을 전달하려면 압축 해제 연산자 anyOf(...$variants)
를 사용하세요.
기본값은 null
입니다. 첫 번째 요소를 기본값으로 만들려면 firstIsDefault()
메서드를 사용하세요.
// default is 'hello'
Expect:: anyOf (Expect:: string ( ' hello ' ), true , null )-> firstIsDefault ();
구조체는 정의된 키가 있는 객체입니다. 이러한 키 => 값 쌍 각각을 "속성"이라고 합니다.
구조체는 배열과 객체를 받아들이고 stdClass
객체를 반환합니다( castTo('array')
등으로 변경하지 않는 한).
기본적으로 모든 속성은 선택 사항이며 기본값은 null
입니다. required()
사용하여 필수 속성을 정의할 수 있습니다.
$ schema = Expect:: structure ([
' required ' => Expect:: string ()-> required (),
' optional ' => Expect:: string (), // the default value is null
]);
$ processor -> process ( $ schema , [ ' optional ' => '' ]);
// ERROR: option 'required' is missing
$ processor -> process ( $ schema , [ ' required ' => ' foo ' ]);
// OK, returns {'required' => 'foo', 'optional' => null}
기본값만 사용하여 속성을 출력하지 않으려면 skipDefaults()
사용하십시오.
$ schema = Expect:: structure ([
' required ' => Expect:: string ()-> required (),
' optional ' => Expect:: string (),
])-> skipDefaults ();
$ processor -> process ( $ schema , [ ' required ' => ' foo ' ]);
// OK, returns {'required' => 'foo'}
optional
속성의 기본값은 null
이지만 입력 데이터에는 허용되지 않습니다(값은 문자열이어야 함). null
허용하는 속성은 nullable()
사용하여 정의됩니다.
$ schema = Expect:: structure ([
' optional ' => Expect:: string (),
' nullable ' => Expect:: string ()-> nullable (),
]);
$ processor -> process ( $ schema , [ ' optional ' => null ]);
// ERROR: 'optional' expects to be string, null given.
$ processor -> process ( $ schema , [ ' nullable ' => null ]);
// OK, returns {'optional' => null, 'nullable' => null}
기본적으로 입력 데이터에는 추가 항목이 있을 수 없습니다.
$ schema = Expect:: structure ([
' key ' => Expect:: string (),
]);
$ processor -> process ( $ schema , [ ' additional ' => 1 ]);
// ERROR: Unexpected item 'additional'
otherItems()
로 변경할 수 있습니다. 매개변수로 각 추가 요소에 대한 스키마를 지정합니다.
$ schema = Expect:: structure ([
' key ' => Expect:: string (),
])-> otherItems (Expect:: int ());
$ processor -> process ( $ schema , [ ' additional ' => 1 ]); // OK
$ processor -> process ( $ schema , [ ' additional ' => true ]); // ERROR
deprecated([string $message])
메서드를 사용하여 속성을 더 이상 사용하지 않을 수 있습니다. $processor->getWarnings()
에 의해 지원 중단 알림이 반환됩니다.
$ schema = Expect:: structure ([
' old ' => Expect:: int ()-> deprecated ( ' The item %path% is deprecated ' ),
]);
$ processor -> process ( $ schema , [ ' old ' => 1 ]); // OK
$ processor -> getWarnings (); // ["The item 'old' is deprecated"]
min()
및 max()
사용하여 배열의 요소 수를 제한합니다.
// array, at least 10 items, maximum 20 items
Expect:: array ()-> min ( 10 )-> max ( 20 );
문자열의 경우 길이를 제한합니다.
// string, at least 10 characters long, maximum 20 characters
Expect:: string ()-> min ( 10 )-> max ( 20 );
숫자의 경우 값을 제한하세요.
// integer, between 10 and 20 inclusive
Expect:: int ()-> min ( 10 )-> max ( 20 );
물론 min()
만 언급하거나 max()
만 언급하는 것도 가능합니다.
// string, maximum 20 characters
Expect:: string ()-> max ( 20 );
pattern()
사용하면 전체 입력 문자열이 일치해야 하는 정규식을 지정할 수 있습니다(즉, ^
a $
문자로 묶인 것처럼).
// just 9 digits
Expect:: string ()-> pattern ( ' d{9} ' );
assert(callable $fn)
사용하여 다른 제한 사항을 추가할 수 있습니다.
$ countIsEven = fn ( $ v ) => count ( $ v ) % 2 === 0 ;
$ schema = Expect:: arrayOf ( ' string ' )
-> assert ( $ countIsEven ); // the count must be even
$ processor -> process ( $ schema , [ ' a ' , ' b ' ]); // OK
$ processor -> process ( $ schema , [ ' a ' , ' b ' , ' c ' ]); // ERROR: 3 is not even
또는
Expect:: string ()-> assert ( ' is_file ' ); // the file must exist
각 어설션에 대한 고유한 설명을 추가할 수 있습니다. 이는 오류 메시지의 일부입니다.
$ schema = Expect:: arrayOf ( ' string ' )
-> assert ( $ countIsEven , ' Even items in array ' );
$ processor -> process ( $ schema , [ ' a ' , ' b ' , ' c ' ]);
// Failed assertion "Even items in array" for item with value array.
이 메서드를 반복적으로 호출하여 여러 제약 조건을 추가할 수 있습니다. 이는 transform()
및 castTo()
호출과 혼합될 수 있습니다.
성공적으로 검증된 데이터는 사용자 정의 기능을 사용하여 수정할 수 있습니다.
// conversion to uppercase:
Expect:: string ()-> transform ( fn ( string $ s ) => strtoupper ( $ s ));
이 메서드를 반복적으로 호출하여 여러 변환을 추가할 수 있습니다. 이는 assert()
및 castTo()
호출과 혼합될 수 있습니다. 작업은 선언된 순서대로 실행됩니다.
Expect:: type ( ' string|int ' )
-> castTo ( ' string ' )
-> assert ( ' ctype_lower ' , ' All characters must be lowercased ' )
-> transform ( fn ( string $ s ) => strtoupper ( $ s )); // conversion to uppercase
transform()
메서드는 값을 동시에 변환하고 유효성을 검사할 수 있습니다. 이는 종종 transform()
과 assert()
연결하는 것보다 간단하고 덜 중복됩니다. 이를 위해 함수는 유효성 검사 문제에 대한 정보를 추가하는 데 사용할 수 있는 addError()
메서드가 있는 NetteSchemaContext 개체를 받습니다.
Expect:: string ()
-> transform ( function ( string $ s , Nette Schema Context $ context ) {
if (! ctype_lower ( $ s )) {
$ context -> addError ( ' All characters must be lowercased ' , ' my.case.error ' );
return null ;
}
return strtoupper ( $ s );
});
성공적으로 검증된 데이터를 캐스팅할 수 있습니다.
Expect:: scalar ()-> castTo ( ' string ' );
기본 PHP 유형 외에도 클래스로 캐스팅할 수도 있습니다. 생성자가 없는 단순한 클래스인지, 생성자가 있는 클래스인지 구분됩니다. 클래스에 생성자가 없으면 인스턴스가 생성되고 구조의 모든 요소가 해당 속성에 기록됩니다.
class Info
{
public bool $ processRefund ;
public int $ refundAmount ;
}
Expect:: structure ([
' processRefund ' => Expect:: bool (),
' refundAmount ' => Expect:: int (),
])-> castTo (Info::class);
// creates '$obj = new Info' and writes to $obj->processRefund and $obj->refundAmount
클래스에 생성자가 있는 경우 구조의 요소는 명명된 매개 변수로 생성자에 전달됩니다.
class Info
{
public function __construct (
public bool $ processRefund ,
public int $ refundAmount ,
) {
}
}
// creates $obj = new Info(processRefund: ..., refundAmount: ...)
스칼라 매개변수와 결합된 형변환은 객체를 생성하고 해당 값을 생성자에 유일한 매개변수로 전달합니다.
Expect:: string ()-> castTo (DateTime::class);
// creates new DateTime(...)
유효성 검사 자체에 앞서 before()
메서드를 사용하여 데이터를 정규화할 수 있습니다. 예를 들어, 문자열 배열(예: ['a', 'b', 'c']
)이어야 하지만 문자열 abc
형식으로 입력을 받는 요소가 있다고 가정해 보겠습니다.
$ explode = fn ( $ v ) => explode ( ' ' , $ v );
$ schema = Expect:: arrayOf ( ' string ' )
-> before ( $ explode );
$ normalized = $ processor -> process ( $ schema , ' a b c ' );
// OK, returns ['a', 'b', 'c']
클래스에서 구조 스키마를 생성할 수 있습니다. 예:
class Config
{
public string $ name ;
public ? string $ password ;
public bool $ admin = false ;
}
$ schema = Expect:: from ( new Config );
$ data = [
' name ' => ' jeff ' ,
];
$ normalized = $ processor -> process ( $ schema , $ data );
// $normalized instanceof Config
// $normalized = {'name' => 'jeff', 'password' => null, 'admin' => false}
익명 클래스도 지원됩니다.
$ schema = Expect:: from ( new class {
public string $ name ;
public ? string $ password ;
public bool $ admin = false ;
});
클래스 정의에서 얻은 정보가 충분하지 않을 수 있으므로 두 번째 매개변수를 사용하여 요소에 대한 사용자 정의 스키마를 추가할 수 있습니다.
$ schema = Expect:: from ( new Config , [
' name ' => Expect:: string ()-> pattern ( ' w:.* ' ),
]);