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

Table::current()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 17
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 17
rs 8.8571
cc 5
eloc 12
nc 6
nop 0
1
<?php
2
namespace frictionlessdata\tableschema;
3
use frictionlessdata\tableschema\Exceptions\DataSourceException;
4
use frictionlessdata\tableschema\Fields\BaseField;
5
6
/**
7
 * represents a data source which validates against a table schema
8
 * provides interfaces for validating the data and iterating over it
9
 * casts all values to their native values according to the table schema
10
 */
11
class Table implements \Iterator
12
{
13
    /**
14
     * @param DataSources\DataSourceInterface $dataSource
15
     * @param Schema $schema
16
     * @throws Exceptions\DataSourceException
17
     */
18
    public function __construct($dataSource, $schema)
19
    {
20
        $this->dataSource = $dataSource;
21
        $this->schema = $schema;
22
        $this->dataSource->open();
23
        $this->uniqueFieldValues = [];
24
    }
25
26
    /**
27
     * @param DataSources\DataSourceInterface $dataSource
28
     * @param Schema $schema
29
     * @param int $numPeekRows
30
     * @return array of validation errors
31
     */
32
    public static function validate($dataSource, $schema, $numPeekRows=10)
33
    {
34
        try {
35
            $table = new static($dataSource, $schema);
36
        } catch (Exceptions\DataSourceException $e) {
37
            return [new SchemaValidationError(SchemaValidationError::LOAD_FAILED, $e->getMessage())];
38
        };
39
        if ($numPeekRows > 0) {
40
            $i = 0;
41
            try {
42
                foreach ($table as $row) {
43
                    if (++$i > $numPeekRows) break;
44
                }
45
            } catch (Exceptions\DataSourceException $e) {
0 ignored issues
show
Unused Code introduced by
catch (\frictionlessdata... $e->getMessage()))); } does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
46
                // general error in getting the next row from the data source
47
                return [new SchemaValidationError(SchemaValidationError::ROW_VALIDATION, [
48
                    "row" => $i,
49
                    "error" => $e->getMessage()
50
                ])];
51
            } catch (Exceptions\FieldValidationException $e) {
52
                // validation error in one of the fields
53
                return array_map(function($validationError) use ($i) {
54
                    return new SchemaValidationError(SchemaValidationError::ROW_FIELD_VALIDATION, [
55
                        "row" => $i+1,
56
                        "field" => $validationError->extraDetails["field"],
57
                        "error" => $validationError->extraDetails["error"],
58
                        "value" => $validationError->extraDetails["value"],
59
                    ]);
60
                }, $e->validationErrors);
61
            }
62
        }
63
        return [];
64
    }
65
66
    /**
67
     * called on each iteration to get the next row
68
     * does validation and casting on the row
69
     * @return mixed[]
70
     * @throws Exceptions\FieldValidationException
71
     * @throws Exceptions\DataSourceException
72
     */
73
    public function current() {
74
        $row = $this->schema->castRow($this->dataSource->getNextLine());
75
        foreach ($this->schema->fields() as $field) {
76
            if ($field->unique()) {
77
                if (!array_key_exists($field->name(), $this->uniqueFieldValues)) {
78
                    $this->uniqueFieldValues[$field->name()] = [];
79
                };
80
                $value = $row[$field->name()];
81
                if (in_array($value, $this->uniqueFieldValues[$field->name()])) {
82
                    throw new DataSourceException("field must be unique", $this->currentLine);
83
                } else {
84
                    $this->uniqueFieldValues[$field->name()][] = $value;
85
                }
86
            }
87
        }
88
        return $row;
89
    }
90
91
    // not interesting, standard iterator functions
92
    // to simplify we prevent rewinding - so you can only iterate once
93
    public function __destruct() {$this->dataSource->close();}
94
    public function rewind() {if ($this->currentLine == 0) {$this->currentLine = 1;} else {throw new \Exception("rewind is not supported");}}
95
    public function key() {return $this->currentLine;}
96
    public function next() {$this->currentLine++;}
97
    public function valid() {return !$this->dataSource->isEof();}
98
99
    protected $currentLine = 0;
100
    protected $dataSource;
101
    protected $schema;
102
    protected $uniqueFieldValues;
103
}