Skip to content

Commit bd13969

Browse files
authored
Merge pull request #19 from swaggest/tweaks
applying default values, refactoring schema process, optimizing few p…
2 parents 32a7a83 + 51ec8e0 commit bd13969

31 files changed

+1154
-617
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ composer.lock
44
composer.phar
55
clover.xml
66
build
7+
/xhprof_report.*
8+
benchmark-result.json

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ before_script:
2323
- test -f $HOME/.composer/cache/composer.lock.$(phpenv version-name) && cp $HOME/.composer/cache/composer.lock.$(phpenv version-name) ./composer.lock || echo "No composer.lock cached"
2424
- composer install --dev --no-interaction --prefer-dist
2525
- test -f $HOME/.composer/cache/composer.lock.$(phpenv version-name) || cp ./composer.lock $HOME/.composer/cache/composer.lock.$(phpenv version-name)
26-
- if [[ $(phpenv version-name) =~ 7.2 ]] ; then test -f $HOME/.composer/cache/phpstan.phar || wget https://github.com/phpstan/phpstan/releases/download/0.9.1/phpstan.phar -O $HOME/.composer/cache/phpstan.phar; fi
26+
- if [[ $(phpenv version-name) =~ 7.2 ]] ; then test -f $HOME/.composer/cache/phpstan.phar || wget https://github.com/phpstan/phpstan/releases/download/0.9.2/phpstan.phar -O $HOME/.composer/cache/phpstan.phar; fi
2727
- if [[ $(phpenv version-name) =~ 7.2 ]] ; then test -f $HOME/.composer/cache/ocular.phar || wget https://scrutinizer-ci.com/ocular.phar -O $HOME/.composer/cache/ocular.phar; fi
2828
- if [[ $(phpenv version-name) =~ 7.2 ]] ; then test -f $HOME/.composer/cache/cctr || wget https://codeclimate.com/downloads/test-reporter/test-reporter-0.1.4-linux-amd64 -O $HOME/.composer/cache/cctr && chmod +x $HOME/.composer/cache/cctr; fi
2929
- if [[ $(phpenv version-name) =~ 7.2 ]] ; then $HOME/.composer/cache/cctr before-build; fi

README.md

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
High definition PHP structures with JSON-schema based validation.
88

99
Supported schemas:
10-
[JSON Schema Draft 7](http://json-schema.org/specification-links.html#draft-7)
11-
[JSON Schema Draft 6](http://json-schema.org/specification-links.html#draft-6)
12-
[JSON Schema Draft 4](http://json-schema.org/specification-links.html#draft-4)
10+
* [JSON Schema Draft 7](http://json-schema.org/specification-links.html#draft-7)
11+
* [JSON Schema Draft 6](http://json-schema.org/specification-links.html#draft-6)
12+
* [JSON Schema Draft 4](http://json-schema.org/specification-links.html#draft-4)
1313

1414
## Installation
1515

@@ -140,6 +140,12 @@ class User extends ClassStructure
140140
// You can embed structures to main level with nested schemas
141141
$properties->info = UserInfo::schema()->nested();
142142

143+
// You can set default value for property
144+
$defaultOptions = new UserOptions();
145+
$defaultOptions->autoLogin = true;
146+
$defaultOptions->groupName = 'guest';
147+
$properties->options = (clone UserOptions::schema())->setDefault(UserOptions::export($defaultOptions));
148+
143149
// Dynamic (phpdoc-defined) properties can be used as well
144150
$properties->quantity = Schema::integer();
145151
$properties->quantity->minimum = 0;
@@ -169,6 +175,21 @@ class UserInfo extends ClassStructure {
169175
}
170176
}
171177

178+
class UserOptions extends ClassStructure
179+
{
180+
public $autoLogin;
181+
public $groupName;
182+
183+
/**
184+
* @param Properties|static $properties
185+
* @param Schema $ownerSchema
186+
*/
187+
public static function setUpProperties($properties, Schema $ownerSchema)
188+
{
189+
$properties->autoLogin = Schema::boolean();
190+
$properties->groupName = Schema::string();
191+
}
192+
}
172193

173194
class Order implements ClassStructureContract
174195
{
@@ -196,7 +217,7 @@ class Order implements ClassStructureContract
196217
$properties->id = Schema::integer();
197218
$properties->userId = User::properties()->id; // referencing property of another schema keeps meta
198219
$properties->dateTime = Schema::string();
199-
$properties->dateTime->format = Schema::FORMAT_DATE_TIME;
220+
$properties->dateTime->format = Format::DATE_TIME;
200221
$properties->price = Schema::number();
201222

202223
$ownerSchema->required[] = self::names()->id;
@@ -422,7 +443,7 @@ $this->assertInstanceOf(CustomSchema::className(), $schema->definitions['User'])
422443

423444
## Code quality and test coverage
424445

425-
Some code quality best practices are intentionally violated here
446+
Some code quality best practices are deliberately violated here
426447
(see [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/swaggest/php-json-schema/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/swaggest/php-json-schema/?branch=master)
427448
) to allow best performance at maintenance cost.
428449

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"swaggest/json-diff": "^2.0"
99
},
1010
"require-dev": {
11-
"phpunit/phpunit": "4.8.23",
11+
"phpunit/phpunit": "4.8.35",
1212
"swaggest/code-builder": "dev-master#e0c5c0612fd241d2d120e5ddef91cda9edc208ee",
1313
"swaggest/php-code-builder": "dev-master#3e643924445eb0f8d13dd011a57a42ce75629892",
1414
"phpunit/php-code-coverage": "2.2.4",

phpstan.neon

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ parameters:
22
ignoreErrors:
33
- '#PHPDoc tag @param references unknown parameter \$schema#'
44
- '#Access to an undefined property static\(Swaggest\\JsonSchema\\JsonSchema\)\|Swaggest\\JsonSchema\\Constraint\\Properties::#'
5+
- '#Accessing property \$skipValidation on possibly null value of type Swaggest\\JsonSchema\\Context\|null#'

src/Constraint/Content.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public static function process(Context $options, $encoding, $mediaType, $data, $
3232
throw new ContentException('Invalid base64 string');
3333
}
3434
$data = base64_decode($data);
35-
if ($data === false) {
35+
if ($data === false && !$options->skipValidation) {
3636
throw new ContentException('Unable to decode base64');
3737
}
3838
break;
@@ -44,7 +44,7 @@ public static function process(Context $options, $encoding, $mediaType, $data, $
4444
case self::MEDIA_TYPE_APPLICATION_JSON:
4545
$data = json_decode($data);
4646
$lastErrorCode = json_last_error();
47-
if ($lastErrorCode !== JSON_ERROR_NONE) {
47+
if (($lastErrorCode !== JSON_ERROR_NONE) && !$options->skipValidation) {
4848
// TODO add readable error message
4949
throw new ContentException('Unable to decode json, err code: ' . $lastErrorCode);
5050
}
@@ -62,7 +62,7 @@ public static function process(Context $options, $encoding, $mediaType, $data, $
6262
case self::MEDIA_TYPE_APPLICATION_JSON:
6363
$data = json_encode($data);
6464
$lastErrorCode = json_last_error();
65-
if ($lastErrorCode !== JSON_ERROR_NONE) {
65+
if (($lastErrorCode !== JSON_ERROR_NONE) && !$options->skipValidation) {
6666
// TODO add readable error message
6767
throw new ContentException('Unable to encode json, err code: ' . $lastErrorCode);
6868
}
@@ -75,7 +75,6 @@ public static function process(Context $options, $encoding, $mediaType, $data, $
7575
case self::ENCODING_BASE64:
7676
$data = base64_encode($data);
7777
break;
78-
7978
}
8079
}
8180

src/Constraint/Format.php

Lines changed: 46 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,67 +8,74 @@
88

99
class Format
1010
{
11-
const DATE_REGEX_PART = '(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])';
12-
const TIME_REGEX_PART = '([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))?';
13-
/**
14-
* @see http://stackoverflow.com/a/1420225
15-
*/
16-
const HOSTNAME_REGEX = '/^
17-
(?=.{1,255}$)
18-
[0-9a-z]
19-
(([0-9a-z]|-){0,61}[0-9a-z])?
20-
(\.[0-9a-z](?:(?:[0-9a-z]|-){0,61}[0-9a-z])?)*
21-
\.?
22-
$/ix';
11+
const DATE_TIME = 'date-time';
12+
const DATE = 'date';
13+
const TIME = 'time';
14+
const URI = 'uri';
15+
const IRI = 'iri';
16+
const EMAIL = 'email';
17+
const IDN_EMAIL = 'idn-email';
18+
const IPV4 = 'ipv4';
19+
const IPV6 = 'ipv6';
20+
const HOSTNAME = 'hostname';
21+
const IDN_HOSTNAME = 'idn-hostname';
22+
const REGEX = 'regex';
23+
const JSON_POINTER = 'json-pointer';
24+
const RELATIVE_JSON_POINTER = 'relative-json-pointer';
25+
const URI_REFERENCE = 'uri-reference';
26+
const IRI_REFERENCE = 'iri-reference';
27+
const URI_TEMPLATE = 'uri-template';
2328

24-
const JSON_POINTER_REGEX = '_^(?:/|(?:/[^/#]*)*)$_';
25-
const JSON_POINTER_RELATIVE_REGEX = '~^(0|[1-9][0-9]*)((?:/[^/#]*)*)(#?)$~';
26-
const JSON_POINTER_UNESCAPED_TILDE = '/~([^01]|$)/';
29+
private static $dateRegexPart = '(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])';
30+
private static $timeRegexPart = '([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(Z|(\+|-)([01][0-9]|2[0-3]):([0-5][0-9]))?';
31+
private static $jsonPointerRegex = '_^(?:/|(?:/[^/#]*)*)$_';
32+
private static $jsonPointerRelativeRegex = '~^(0|[1-9][0-9]*)((?:/[^/#]*)*)(#?)$~';
33+
private static $jsonPointerUnescapedTilde = '/~([^01]|$)/';
2734

2835
public static function validationError($format, $data)
2936
{
3037
switch ($format) {
31-
case 'date-time':
38+
case self::DATE_TIME:
3239
return self::dateTimeError($data);
33-
case 'date':
34-
return preg_match('/^' . self::DATE_REGEX_PART . '$/i', $data) ? null : 'Invalid date';
35-
case 'time':
36-
return preg_match('/^' . self::TIME_REGEX_PART . '$/i', $data) ? null : 'Invalid time';
37-
case 'uri':
40+
case self::DATE:
41+
return preg_match('/^' . self::$dateRegexPart . '$/i', $data) ? null : 'Invalid date';
42+
case self::TIME:
43+
return preg_match('/^' . self::$timeRegexPart . '$/i', $data) ? null : 'Invalid time';
44+
case self::URI:
3845
return Uri::validationError($data, Uri::IS_SCHEME_REQUIRED);
39-
case 'iri':
46+
case self::IRI:
4047
return Iri::validationError($data);
41-
case 'email':
48+
case self::EMAIL:
4249
return filter_var($data, FILTER_VALIDATE_EMAIL) ? null : 'Invalid email';
43-
case 'idn-email':
50+
case self::IDN_EMAIL:
4451
return count(explode('@', $data, 3)) === 2 ? null : 'Invalid email';
45-
case 'ipv4':
52+
case self::IPV4:
4653
return filter_var($data, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) ? null : 'Invalid ipv4';
47-
case 'ipv6':
54+
case self::IPV6:
4855
return filter_var($data, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? null : 'Invalid ipv6';
49-
case 'hostname':
50-
return preg_match(self::HOSTNAME_REGEX, $data) ? null : 'Invalid hostname';
51-
case 'idn-hostname':
56+
case self::HOSTNAME:
57+
return preg_match(Uri::HOSTNAME_REGEX, $data) ? null : 'Invalid hostname';
58+
case self::IDN_HOSTNAME:
5259
return IdnHostname::validationError($data);
53-
case 'regex':
60+
case self::REGEX:
5461
return self::regexError($data);
55-
case 'json-pointer':
62+
case self::JSON_POINTER:
5663
return self::jsonPointerError($data);
57-
case 'relative-json-pointer':
64+
case self::RELATIVE_JSON_POINTER:
5865
return self::jsonPointerError($data, true);
59-
case 'uri-reference':
66+
case self::URI_REFERENCE:
6067
return Uri::validationError($data, Uri::IS_URI_REFERENCE);
61-
case 'iri-reference':
68+
case self::IRI_REFERENCE:
6269
return Iri::validationError($data, Uri::IS_URI_REFERENCE);
63-
case 'uri-template':
70+
case self::URI_TEMPLATE:
6471
return Uri::validationError($data, Uri::IS_URI_TEMPLATE);
6572
}
6673
return null;
6774
}
6875

6976
public static function dateTimeError($data)
7077
{
71-
return preg_match('/^' . self::DATE_REGEX_PART . 'T' . self::TIME_REGEX_PART . '$/i', $data)
78+
return preg_match('/^' . self::$dateRegexPart . 'T' . self::$timeRegexPart . '$/i', $data)
7279
? null
7380
: 'Invalid date-time: ' . $data;
7481
}
@@ -95,13 +102,13 @@ public static function regexError($data)
95102

96103
public static function jsonPointerError($data, $isRelative = false)
97104
{
98-
if (preg_match(self::JSON_POINTER_UNESCAPED_TILDE, $data)) {
105+
if (preg_match(self::$jsonPointerUnescapedTilde, $data)) {
99106
return 'Invalid json-pointer: unescaped ~';
100107
}
101108
if ($isRelative) {
102-
return preg_match(self::JSON_POINTER_RELATIVE_REGEX, $data) ? null : 'Invalid relative json-pointer';
109+
return preg_match(self::$jsonPointerRelativeRegex, $data) ? null : 'Invalid relative json-pointer';
103110
} else {
104-
return preg_match(self::JSON_POINTER_REGEX, $data) ? null : 'Invalid json-pointer';
111+
return preg_match(self::$jsonPointerRegex, $data) ? null : 'Invalid json-pointer';
105112
}
106113
}
107114
}

src/Constraint/Format/IdnHostname.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
namespace Swaggest\JsonSchema\Constraint\Format;
44

5-
use Swaggest\JsonSchema\Constraint\Format;
6-
75
class IdnHostname
86
{
97
/**
@@ -18,6 +16,6 @@ public static function validationError($data)
1816
if ($error !== null) {
1917
return $error;
2018
}
21-
return preg_match(Format::HOSTNAME_REGEX, $sanitized) ? null : 'Invalid idn-hostname: ' . $data;
19+
return preg_match(Uri::HOSTNAME_REGEX, $sanitized) ? null : 'Invalid idn-hostname: ' . $data;
2220
}
2321
}

src/Constraint/Format/Uri.php

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
<?php
2-
/**
3-
* Created by PhpStorm.
4-
* User: vpoturaev
5-
* Date: 1/19/18
6-
* Time: 15:05
7-
*/
82

93
namespace Swaggest\JsonSchema\Constraint\Format;
104

11-
12-
use Swaggest\JsonSchema\Constraint\Format;
13-
145
class Uri
156
{
7+
/**
8+
* @see http://stackoverflow.com/a/1420225
9+
*/
10+
const HOSTNAME_REGEX = '/^
11+
(?=.{1,255}$)
12+
[0-9a-z]
13+
(([0-9a-z]|-){0,61}[0-9a-z])?
14+
(\.[0-9a-z](?:(?:[0-9a-z]|-){0,61}[0-9a-z])?)*
15+
\.?
16+
$/ix';
17+
1618
const IS_URI_REFERENCE = 1;
1719
const IS_URI_TEMPLATE = 2;
1820
const IS_SCHEME_REQUIRED = 8;
@@ -50,7 +52,7 @@ public static function validationError($data, $options = 0)
5052
}
5153
if (isset($uri['host'])) {
5254
$host = $uri['host'];
53-
if (!preg_match(Format::HOSTNAME_REGEX, $host)) {
55+
if (!preg_match(self::HOSTNAME_REGEX, $host)) {
5456
// stripping [ ]
5557
if ($host[0] === '[' && $host[strlen($host) - 1] === ']') {
5658
$host = substr($host, 1, -1);

src/Constraint/Properties.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public function setAdditionalProperties(Schema $additionalProperties = null)
6767

6868

6969
/** @var Egg[][] */
70-
private $nestedProperties = array();
70+
public $nestedProperties = array();
7171

7272
/** @var Schema[] */
7373
public $nestedPropertyNames = array();

0 commit comments

Comments
 (0)