Completed
Branch master (7d7b3f)
by Ori
01:38
created

BaseValidator::validateSchema()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace frictionlessdata\datapackage\Validators;
4
5
use frictionlessdata\datapackage\Registry;
6
use frictionlessdata\datapackage\Utils;
7
use frictionlessdata\tableschema\SchemaValidator;
8
use frictionlessdata\tableschema\SchemaValidationError;
9
10
abstract class BaseValidator extends SchemaValidator
11
{
12
    public function __construct($descriptor, $basePath = null)
13
    {
14
        $this->basePath = $basePath;
15
        parent::__construct($descriptor);
16
    }
17
18
    /**
19
     * validate a descriptor.
20
     *
21
     * @param object $descriptor
22
     * @param string $basePath
23
     *
24
     * @return \frictionlessdata\tableschema\SchemaValidationError[]
25
     */
26
    public static function validate($descriptor, $basePath = null)
27
    {
28
        $validator = new static($descriptor, $basePath);
29
30
        return $validator->getValidationErrors();
31
    }
32
33
    protected $basePath;
34
35
    /**
36
     * should be implemented properly by extending classes
37
     * should return the profile used for validation
38
     * if using the default getValidationSchemaUrl function - this value should correspond to a file in schemas/ directory.
39
     *
40
     * @return string
41
     */
42
    protected function getValidationProfile()
43
    {
44
        return $this->descriptor->profile;
0 ignored issues
show
Bug introduced by
The property descriptor does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
45
    }
46
47
    protected function convertValidationSchemaFilenameToUrl($filename)
48
    {
49
        $filename = realpath($filename);
50
        if (file_exists($filename)) {
51
            return 'file://'.$filename;
52
        } else {
53
            throw new \Exception("failed to find schema file: '{$filename}' for descriptor ".json_encode($this->descriptor));
54
        }
55
    }
56
57
    protected function getJsonSchemaFileFromRegistry($profile)
58
    {
59
        return false;
60
    }
61
62
    /**
63
     * get the url which the schema for validation can be fetched from.
64
     *
65
     * @return string
66
     */
67
    protected function getValidationSchemaUrl()
68
    {
69
        $profile = $this->getValidationProfile();
70
        if ($filename = $this->getJsonSchemaFileFromRegistry($profile)) {
71
            // known profile id in the registry
72
            return $this->convertValidationSchemaFilenameToUrl($filename);
73
        } elseif (Utils::isHttpSource($profile)) {
74
            // url
75
            return $profile;
76
        } elseif (file_exists($filename = $this->basePath.DIRECTORY_SEPARATOR.$profile)) {
77
            // relative path - prefixed with basePath
78
            return $this->convertValidationSchemaFilenameToUrl($filename);
79
        } else {
80
            // absolute path (or relative to current working directory)
81
            return $this->convertValidationSchemaFilenameToUrl($profile);
82
        }
83
    }
84
85
    /**
86
     * Allows to specify different error classes for different validators.
87
     *
88
     * @return string
89
     */
90
    protected function getSchemaValidationErrorClass()
91
    {
92
        return 'frictionlessdata\\tableschema\\SchemaValidationError';
93
    }
94
95
    /**
96
     * allows extending classes to modify the descriptor before passing to the validator.
97
     *
98
     * @return object
99
     */
100
    protected function getDescriptorForValidation()
101
    {
102
        return $this->descriptor;
103
    }
104
105
    /**
106
     * conver the validation error message received from JsonSchema to human readable string.
107
     *
108
     * @param array $error
109
     *
110
     * @return string
111
     */
112
    protected function getValidationErrorMessage($error)
113
    {
114
        return sprintf('[%s] %s', $error['property'], $error['message']);
115
    }
116
117
    /**
118
     * does the validation, adds errors to the validator object using _addError method.
119
     */
120
    protected function validateSchema()
121
    {
122
        $this->validateSchemaUrl($this->getValidationSchemaUrl());
123
    }
124
125
    protected function validateSchemaUrl($url)
126
    {
127
        $validator = new \JsonSchema\Validator();
128
        $descriptor = $this->getDescriptorForValidation();
129
        $validator->validate($descriptor, (object) ['$ref' => $url]);
130
        if (!$validator->isValid()) {
131
            foreach ($validator->getErrors() as $error) {
132
                $this->addError(
133
                    SchemaValidationError::SCHEMA_VIOLATION,
134
                    $this->getValidationErrorMessage($error)
135
                );
136
            }
137
        }
138
    }
139
140
    /**
141
     * Add an error to the validator object - errors are aggregated and returned by validate function.
142
     *
143
     * @param int        $code
144
     * @param null|mixed $extraDetails
145
     */
146
    protected function addError($code, $extraDetails = null)
147
    {
148
        // modified from parent function to support changing the error class
149
        $errorClass = $this->getSchemaValidationErrorClass();
150
        $this->errors[] = new $errorClass($code, $extraDetails);
0 ignored issues
show
Bug introduced by
The property errors does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
151
    }
152
153
    protected function validateKeys()
154
    {
155
        // this can be used to do further validations on $this->descriptor
156
        // it will run only in case validateSchema succeeded
157
        // so no need to check if attribute exists or in correct type
158
        // the parent SchemaValidator does some checks specific to table schema - so don't call the parent function
159
    }
160
}
161