Completed
Pull Request — develop (#15)
by Narcotic
13:08
created

Validator::validate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 11
ccs 6
cts 6
cp 1
rs 9.4285
cc 2
eloc 6
nc 2
nop 2
crap 2
1
<?php
2
/**
3
 * Validator class file
4
 */
5
6
namespace Graviton\JsonSchemaBundle\Validator;
7
8
use Graviton\JsonSchemaBundle\Exception\ValidationExceptionError;
9
10
/**
11
 * JSON definition validation
12
 *
13
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
14
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
15
 * @link     http://swisscom.ch
16
 */
17
class Validator implements ValidatorInterface
18
{
19
    /**
20
     * @var \stdClass JSON schema
21
     */
22
    private $schema;
23
    /**
24
     * @var Validator Validator
25
     */
26
    private $validator;
27
28
    /**
29
     * Constructor
30
     *
31
     * @param Validator $validator Validator
32
     * @param \stdClass $schema    JSON schema
33
     */
34 4
    public function __construct($validator, $schema)
35
    {
36 4
        $this->validator = $validator;
37 4
        $this->schema = $schema;
38 4
    }
39
40
    /**
41
     * Validate raw JSON definition
42
     *
43
     * @param string $json JSON definition
44
     * @return ValidationExceptionError[]
45
     * @throws InvalidJsonException If JSON is not valid
46
     */
47 4
    public function validateJsonDefinition($json)
48
    {
49 4
        $json = json_decode($json);
50 4
        if (json_last_error() !== JSON_ERROR_NONE) {
51 1
            throw new InvalidJsonException(sprintf('Malformed JSON: %s', $this->getJsonLastErrorMessage()));
52
        }
53 3
        if (!is_object($json)) {
54 1
            throw new InvalidJsonException('JSON value must be an object');
55
        }
56
57 2
        return $this->validate($json, $this->schema);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->validate($json, $this->schema); (Graviton\JsonSchemaBundl...idationExceptionError[]) is incompatible with the return type declared by the interface Graviton\JsonSchemaBundl...:validateJsonDefinition of type HadesArchitect\JsonSchemaBundle\Error\Error[].

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
58
    }
59
60
    /**
61
     * validate a json structure with a schema
62
     *
63
     * @param object $json   the json
64
     * @param object $schema the schema
65
     *
66
     * @return ValidationExceptionError[] errors
67
     */
68 2
    public function validate($json, $schema)
69
    {
70 2
        $this->validator->reset();
0 ignored issues
show
Bug introduced by
The method reset() does not seem to exist on object<Graviton\JsonSche...le\Validator\Validator>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
71 2
        $this->validator->check($json, $schema);
0 ignored issues
show
Bug introduced by
The method check() does not seem to exist on object<Graviton\JsonSche...le\Validator\Validator>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
72
73 2
        if ($this->validator->isValid()) {
0 ignored issues
show
Bug introduced by
The method isValid() does not seem to exist on object<Graviton\JsonSche...le\Validator\Validator>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
74 1
            return [];
75
        }
76
77 1
        return $this->getErrors();
78
    }
79
80
    /**
81
     * Wraps the array exception in our own class
82
     *
83
     * @return ValidationExceptionError[]
84
     */
85 1
    public function getErrors()
86
    {
87 1
        $errors = [];
88 1
        foreach ($this->validator->getErrors() as $error) {
89 1
            $errors[] = new ValidationExceptionError($error);
90 1
        }
91 1
        return $errors;
92
    }
93
94
    /**
95
     * Get JSON decode last error message
96
     *
97
     * @return string
98
     */
99 1
    private function getJsonLastErrorMessage()
100
    {
101 1
        if (function_exists('json_last_error_msg')) {
102 1
            return json_last_error_msg();
103
        }
104
105
        $errorNo = json_last_error();
106
        $errorMap = [
107
            JSON_ERROR_DEPTH            => 'Maximum stack depth exceeded',
108
            JSON_ERROR_STATE_MISMATCH   => 'Underflow or modes mismatch',
109
            JSON_ERROR_CTRL_CHAR        => 'Unexpected control character found',
110
            JSON_ERROR_SYNTAX           => 'Syntax error, malformed JSON',
111
            JSON_ERROR_UTF8             => 'Malformed UTF-8 characters, possibly incorrectly encoded',
112
        ];
113
        return isset($errorMap[$errorNo]) ? $errorMap[$errorNo]: 'Unknown error';
114
    }
115
}
116