Completed
Push — master ( 29cde4...77c4c6 )
by Ori
03:02
created

Schema::foreignKeys()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
rs 10
cc 2
eloc 2
nc 2
nop 0
1
<?php
2
namespace frictionlessdata\tableschema;
3
4
/**
5
 *  Table Schema representation.
6
 *  Loads and validates a Table Schema descriptor from a descriptor / path to file / url containing the descriptor
7
 */
8
class Schema
9
{
10
    protected $DEFAULT_FIELD_CLASS = "\\frictionlessdata\\tableschema\\Fields\\StringField";
11
12
    /**
13
     * Schema constructor.
14
     * @param mixed $descriptor
15
     * @throws Exceptions\SchemaLoadException
16
     * @throws Exceptions\SchemaValidationFailedException
17
     */
18
    public function __construct($descriptor)
19
    {
20
        if (Utils::isJsonString($descriptor)) {
21
            // it's a json encoded string
22
            try {
23
                $this->descriptor = json_decode($descriptor);
24
            } catch (\Exception $e) {
25
                throw new Exceptions\SchemaLoadException($descriptor, null, $e->getMessage());
26
            }
27
        } elseif (is_string($descriptor)) {
28
            // it's a url or file path
29
            $descriptorSource = $descriptor;
30
            try {
31
                $descriptor = file_get_contents($descriptorSource);
32
            } catch (\Exception $e) {
33
                throw new Exceptions\SchemaLoadException(null, $descriptorSource, $e->getMessage());
34
            }
35
            try {
36
                $this->descriptor = json_decode($descriptor);
37
            } catch (\Exception $e) {
38
                throw new Exceptions\SchemaLoadException($descriptor, $descriptorSource, $e->getMessage());
39
            }
40
        } else {
41
            $this->descriptor = $descriptor;
42
        }
43
        if (!is_object($this->descriptor())) {
44
            throw new Exceptions\SchemaLoadException($descriptor, null, "descriptor must be an object");
45
        }
46
        $validationErrors = SchemaValidator::validate($this->descriptor());
47
        if (count($validationErrors) > 0) {
48
            throw new Exceptions\SchemaValidationFailedException($validationErrors);
49
        };
50
    }
51
52
    /**
53
     * loads and validates the given descriptor source (php object / string / path to file / url)
54
     * returns an array of validation error objects
55
     * @param mixed $descriptor
56
     * @return array
57
     */
58
    public static function validate($descriptor)
59
    {
60
        try {
61
            new static($descriptor);
62
            return [];
63
        } catch (Exceptions\SchemaLoadException $e) {
64
            return [
65
                new SchemaValidationError(SchemaValidationError::LOAD_FAILED, $e->getMessage())
66
            ];
67
        } catch (Exceptions\SchemaValidationFailedException $e) {
68
            return $e->validationErrors;
69
        }
70
    }
71
72
    /**
73
     * @return object
74
     */
75
    public function descriptor()
76
    {
77
        return $this->descriptor;
78
    }
79
80
    public function fullDescriptor()
81
    {
82
        $fullDescriptor = $this->descriptor();
83
        $fullFieldDescriptors = [];
84
        foreach ($this->fields() as $field) {
85
            $fullFieldDescriptors[] = $field->fullDescriptor();
86
        }
87
        $fullDescriptor->fields = $fullFieldDescriptors;
88
        $fullDescriptor->missingValues = $this->missingValues();
89
        return $fullDescriptor;
90
    }
91
92
    public function field($name)
93
    {
94
        $fields = $this->fields();
95
        if (array_key_exists($name, $fields)) {
96
            return $fields[$name];
97
        } else {
98
            throw new \Exception("unknown field name: {$name}");
99
        }
100
    }
101
102
    /**
103
     * @return Fields\BaseField[] array of field name => field object
104
     */
105
    public function fields()
106
    {
107
        if (empty($this->fieldsCache)) {
108
            foreach ($this->descriptor()->fields as $fieldDescriptor) {
109
                if (!array_key_exists("type", $fieldDescriptor)) {
110
                    $field = new $this->DEFAULT_FIELD_CLASS($fieldDescriptor);
111
                } else {
112
                    $field = Fields\FieldsFactory::field($fieldDescriptor);
113
                }
114
                $this->fieldsCache[$field->name()] = $field;
115
            }
116
        }
117
        return $this->fieldsCache;
118
    }
119
120
    public function missingValues()
121
    {
122
        return isset($this->descriptor()->missingValues) ? $this->descriptor()->missingValues : [""];
123
    }
124
125
    public function primaryKey()
126
    {
127
        return isset($this->descriptor()->primaryKey) ? $this->descriptor()->primaryKey : [];
128
    }
129
130
    public function foreignKeys()
131
    {
132
        return isset($this->descriptor()->foreignKeys) ? $this->descriptor()->foreignKeys : [];
133
    }
134
135
    /**
136
     * @param mixed[] $row
137
     * @return mixed[]
138
     * @throws Exceptions\FieldValidationException
139
     */
140
    public function castRow($row)
141
    {
142
        $outRow = [];
143
        $validationErrors = [];
144
        foreach ($this->fields() as $fieldName => $field) {
145
            $value = array_key_exists($fieldName, $row) ? $row[$fieldName] : null;
146
            if (in_array($value, $this->missingValues())) $value = null;
147
            try {
148
                $outRow[$fieldName] = $field->castValue($value);
149
            } catch (Exceptions\FieldValidationException $e) {
150
                $validationErrors = array_merge($validationErrors, $e->validationErrors);
151
            }
152
        }
153
        if (count($validationErrors) > 0) {
154
            throw new Exceptions\FieldValidationException($validationErrors);
155
        }
156
        return $outRow;
157
    }
158
159
    /**
160
     * @param array $row
161
     * @return SchemaValidationError[]
162
     */
163
    public function validateRow($row)
164
    {
165
        try {
166
            $this->castRow($row);
167
            return [];
168
        } catch (Exceptions\FieldValidationException $e) {
169
            return $e->validationErrors;
170
        }
171
    }
172
173
    public function save($filename)
174
    {
175
        file_put_contents($filename, json_encode($this->fullDescriptor()));
176
    }
177
178
    protected $descriptor;
179
    protected $fieldsCache = null;
180
}