Validator   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 103
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 76.47%

Importance

Changes 0
Metric Value
wmc 12
lcom 1
cbo 2
dl 0
loc 103
ccs 26
cts 34
cp 0.7647
rs 10
c 0
b 0
f 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A getErrors() 0 8 2
A getJsonLastErrorMessage() 0 16 3
A validateJsonDefinition() 0 12 3
A validate() 0 15 3
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  https://opensource.org/licenses/MIT MIT License
15
 * @link     http://swisscom.ch
16
 */
17
class Validator implements ValidatorInterface
18
{
19
    /**
20
     * @var string JSON schema location
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 string    $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 Graviton\JsonSchemaBundle\Validator\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...
Documentation introduced by
$this->schema is of type string, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

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