Passed
Push — master ( 21e99f...8493af )
by George
03:07
created

Analyse::validate()   D

Complexity

Conditions 9
Paths 16

Size

Total Lines 34
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 9.4867

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 34
ccs 18
cts 22
cp 0.8182
rs 4.909
cc 9
eloc 18
nc 16
nop 1
crap 9.4867
1
<?php
2
namespace JsonTable\Analyse;
3
4
use \JsonTable\Base;
5
6
/**
7
 * Analyse data to ensure it validates against a JSON table schema.
8
 *
9
 * @package    JSON table
10
 */
11
class Analyse extends Base implements AnalyseInterface
12
{
13
    /**
14
     * @var string The description for missing mandatory columns.
15
     */
16
    const ERROR_REQUIRED_COLUMN_MISSING = '<strong>%d</strong> required column(s) missing:';
17
18
    /**
19
     * @var string The description for CSV columns that are not in the schema.
20
     */
21
    const ERROR_UNSPECIFIED_COLUMN = '<strong>%d</strong> unexpected column(s):';
22
23
    /**
24
     * @var string The description for rows with missing columns.
25
     */
26
    const ERROR_INCORRECT_COLUMN_COUNT = 'There are the wrong number of columns';
27
28
    /**
29
     * @var string The description for rows with missing columns.
30
     */
31
    const ERROR_REQUIRED_FIELD_MISSING_DATA = 'There are <strong>%d</strong> required fields with missing data:';
32
33
    /**
34
     * @var string The format validation type.
35
     */
36
    const VALIDATION_TYPE_FORMAT = 'Format';
37
38
    /**
39
     * @var string The foreign key validation type.
40
     */
41
    const VALIDATION_TYPE_FOREIGN_KEY = 'ForeignKey';
42
43
    /**
44
     * @var boolean Should the analysis stop when an error is found.
45
     */
46
    protected $stopIfInvalid;
47
48
    /**
49
     * @var Statistics  Statistics information regarding the analysis.
50
     */
51
    protected $statistics;
52
53
    /**
54
     * @var Error  Details of errors found during the analysis.
55
     */
56
    protected $error;
57
58
59
    /**
60
     * Set the dependencies if they've been provided.
61
     *
62
     * @param   Statistics  $statistics Statistics information regarding the analysis. Optional.
63
     * @param   Error       $error      Details of errors found during the analysis. Optional.
64
     */
65 41
    public function __construct(Statistics $statistics = null, Error $error = null)
66
    {
67 41
        $this->statistics = (is_null($statistics)) ? new Statistics() : $statistics;
68 41
        $this->error = (is_null($error)) ? new Error() : $error;
69 41
    }
70
71
72
    /**
73
     * Analyse the specified file against the loaded schema.
74
     *
75
     * @param   boolean $stopIfInvalid Should the analysis stop when the file is found to be invalid.
76
     *                                          The default is false.
77
     *
78
     * @return  boolean true if the file passes the validation and false if not.
79
     */
80 30
    public function validate($stopIfInvalid = false)
81
    {
82 30
        $this->stopIfInvalid = (bool) $stopIfInvalid;
83
84 30
        $continueAnalysis = true;
85
86 30
        self::openFile();
87 30
        self::setCsvHeaderColumns();
88
89 30
        $analyseColumns = new Column($this->statistics, $this->error);
90
91 30
        if (!$analyseColumns->validate()) {
92 2
            $continueAnalysis = false;
93 2
        }
94
95 30
        $analyseLexical = new Lexical($this->statistics, $this->error);
96
97 30
        if ($continueAnalysis && !$analyseLexical->validate() && $this->stopIfInvalid) {
98
            $continueAnalysis = false;
99
        }
100
101 30
        $analysePrimaryKey = new PrimaryKey($this->statistics, $this->error);
102
        
103 30
        if ($continueAnalysis && !$analysePrimaryKey->validate() && $this->stopIfInvalid) {
104
            $continueAnalysis = false;
105
        }
106
107 30
        if ($continueAnalysis) {
108 28
            $analyseForeignKey = new ForeignKey($this->statistics, $this->error);
109 28
            $analyseForeignKey->validate();
110 28
        }
111
112 30
        return $this->isFileValid();
113
    }
114
115
116
    /**
117
     * Return all errors.
118
     *
119
     * @return  array   The error messages.
120
     */
121 2
    public function getErrors()
122
    {
123 2
        return $this->error->getErrors();
124
    }
125
126
127
    /**
128
     * Return the statistics about this analysis.
129
     *
130
     * @return  array   The statistics.
131
     */
132 10
    public function getStatistics()
133
    {
134 10
        return $this->statistics->getStatistics();
135
    }
136
137
138
    /**
139
     * Check if the specified column is mandatory.
140
     *
141
     * @param   object  $schemaColumn    The schema column object to examine.
142
     *
143
     * @return  boolean Whether the column is mandatory.
144
     */
145 30
    protected function isColumnMandatory($schemaColumn)
146
    {
147 30
        $propertyExists = property_exists($schemaColumn, 'constraints') &&
148 30
                              property_exists($schemaColumn->constraints, 'required') &&
149 30
                              (true === $schemaColumn->constraints->required);
150 30
        return $propertyExists;
151
    }
152
153
154
    /**
155
     * Load and instantiate the specified validator.
156
     *
157
     * @param string $validationType The type of validator to load.
158
     * @param string $type The type being validated.
159
     *                            For formats this will be the field type.
160
     *                            For foreign keys this will be the datapackage type
161
     *
162
     * @return object The validation object. Throws an exception on error.
163
     *
164
     * @throws  \Exception if the validator file couldn't be loaded.
165
     * @throws  \Exception if the validator class definition couldn't be found.
166
     */
167 28
    protected function instantiateValidator($validationType, $type)
168
    {
169
        // For format validation, "Date", "datetime" and "time" all follow the same schema definition rules
170
        // so just use the datetime format for them all.
171 28
        if (Analyse::VALIDATION_TYPE_FORMAT === $validationType && ('date' === $type || 'time' === $type)) {
172 2
            $type = 'datetime';
173 2
        }
174
175 28
        $typeClassName = ucwords($type) . 'Validator';
176 28
        $validatorFile = dirname(dirname(__FILE__)) . "/Validate/$validationType/$typeClassName.php";
177
178 28
        if (!file_exists($validatorFile) || !is_readable($validatorFile)) {
179
            throw new \Exception("Could not load the validator file for $validationType $type.");
180
        }
181
182 28
        include_once $validatorFile;
183
184 28
        $validatorClass = "\\JsonTable\\Validate\\$validationType\\$typeClassName";
185
186 28
        if (!class_exists($validatorClass)) {
187
            throw new \Exception("Could not find the validator class $validatorClass");
188
        }
189
190 28
        return new $validatorClass($type);
191
    }
192
193
194
    /**
195
     * Check if the file was found to be valid.
196
     * This checks for any validation errors.
197
     *
198
     * @return  boolean Is the file valid.
199
     */
200 30
    private function isFileValid()
201
    {
202 30
        return (0 === count($this->error->getErrors()));
203
    }
204
}
205