Passed
Push — master ( 46473c...5fda7a )
by George
03:23
created

PrimaryKey::handleDuplicateHash()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 9.6666
cc 1
eloc 6
nc 1
nop 1
crap 1
1
<?php
2
namespace JsonTable\Analyse;
3
4
/**
5
 * Perform primary key analysis.
6
 *
7
 * @package JsonTable
8
 */
9
class PrimaryKey extends Analyse implements AnalyseInterface
10
{
11
    /**
12
     * @var string The description for fields with duplicated primary keys.
13
     */
14
    const ERROR_DUPLICATE_PRIMARY_KEY = 'There are <strong>%d</strong> rows that have duplicated primary keys:';
15
16
    /**
17
     * @var array   The current CSV row being analysed.
18
     */
19
    private $currentCsvRow;
20
21
    /**
22
     * @var int The position of the current CSV row row in the CSV file.
23
     */
24
    private $rowNumber;
25
26
    /**
27
     * @var array   The primary keys for every row in the file.
28
     */
29
    private $fileKeys;
30
31
    /**
32
     * @var array   The primary key parts for the current row.
33
     */
34
    private $rowKeyParts;
35
36
    /**
37
     * @var array   The primary key fields.
38
     */
39
    private $primaryKeyFields;
40
41
    /**
42
     * @var string  The name of the primary key field currently being analysed.
43
     */
44
    private $primaryKeyFieldName;
45
46
    /**
47
     * @var string  The hash of the data taken from the primary key fields in the current CSV row.
48
     */
49
    private $hash;
50
51
52
    /**
53
     * Validate that any specified primary key constraints have been met.
54
     *
55
     * @return  boolean Does the data meet the primary key constraints.
56
     *
57
     *
58
     */
59 74
    public function validate()
60
    {
61 74
        if (false === property_exists(parent::$schemaJson, 'primaryKey')) {
62 1
            return true;
63
        }
64
65 73
        $this->setPrimaryKeyFields();
66 73
        $this->fileKeys = [];
67
68 73
        self::rewindFilePointerToFirstData();
69
70 73
        $this->rowNumber= 1;
71
72 73
        while ($currentCsvRow = parent::loopThroughFileRows()) {
73 73
            $this->currentCsvRow = $currentCsvRow;
74 73
            $this->getPrimaryKeyDataForRow();
75 73
            $this->createHash();
76
77 73
            if ($existingKey = $this->isHashUnique()) {
78 1
                $this->handleDuplicateHash($existingKey);
79
80 1
                if ($this->stopIfInvalid) {
81
                    return false;
82
                }
83 1
            }
84
85 73
            $this->fileKeys[$this->rowNumber] = $this->hash;
86 73
            $this->rowNumber++;
87 73
        }
88
89 73
        return true;
90
    }
91
92
93
    /**
94
     * Set the primary key fields.
95
     *
96
     * @return  void
97
     */
98 73
    private function setPrimaryKeyFields()
99
    {
100 73
        $this->primaryKeyFields = (array) parent::$schemaJson->primaryKey;
101 73
    }
102
103
104
    /**
105
     * Check that there is a column in the JSON table schema file for the current primary key field.
106
     *
107
     * @return  void
108
     *
109
     * @throws  \Exception if the primary key was not in the schema file.
110
     */
111 73
    private function checkColumnExistsInSchema()
112
    {
113 73
        if (false === $this->getSchemaKeyFromName($this->primaryKeyFieldName)) {
114
            throw new \Exception("The primary key &quot;$this->primaryKeyFieldName&quot; was not in the file.
115
                    Primary key columns should be set as required.");
116
        }
117 73
    }
118
119
120
    /**
121
     * Get the data in the CSV column for the current primary key column.
122
     *
123
     * @return  string  The data in the column.
124
     */
125 73
    private function csvDataForPrimaryKeyColumn()
126
    {
127 73
        $csvPosition = $this->getCsvPositionFromName($this->primaryKeyFieldName);
128 73
        return $this->currentCsvRow[$csvPosition];
129
    }
130
131
132
    /**
133
     * Get the data in the primary key columns for the current CSV row.
134
     *
135
     * @return  void
136
     */
137 73
    private function getPrimaryKeyDataForRow()
138
    {
139 73
        $this->rowKeyParts = [];
140
141 73
        foreach ($this->primaryKeyFields as $fieldName) {
142 73
            $this->primaryKeyFieldName = strtolower($fieldName);
143 73
            $this->checkColumnExistsInSchema();
144 73
            $this->rowKeyParts[] = $this->csvDataForPrimaryKeyColumn();
145 73
        }
146 73
    }
147
148
149
    /**
150
     * Create a hash of the data taken from the primary key fields in the current CSV row.
151
     *
152
     * @return  void
153
     */
154 73
    private function createHash()
155
    {
156 73
        $this->hash = implode(', ', $this->rowKeyParts);
157 73
    }
158
159
160
    /**
161
     * Check whether the current hash has already been created for this file.
162
     *
163
     * @return  boolean|int False if this row's primary key hash is unique
164
     *                      or the number of the row with the same hash if it's not.
165
     */
166 73
    private function isHashUnique()
167
    {
168 73
        return array_search($this->hash, $this->fileKeys);
169
    }
170
171
172
    /**
173
     * Handle the current hash not being unique.
174
     *
175
     * @param   int $existingKey    The number of the row with the same hash.
176
     *
177
     * @return  void
178
     */
179 1
    private function handleDuplicateHash($existingKey)
180
    {
181 1
        $primaryKeyColumns = implode(', ', $this->primaryKeyFields);
182
        $errorMessage = "The data in columns &quot;$primaryKeyColumns&quot; should be unique,
183 1
                but rows $existingKey &amp; $this->rowNumber have the same values of &quot;$this->hash&quot;";
184
185 1
        $this->error->setError(self::ERROR_DUPLICATE_PRIMARY_KEY, $errorMessage);
186 1
        $this->statistics->setErrorRow($this->rowNumber);
187
    }
188
}