Conditions | 16 |
Paths | 352 |
Total Lines | 95 |
Code Lines | 59 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
1 | <?php |
||
127 | public function upsert($table, $input, $compare) { |
||
128 | |||
129 | $this->conn->beginTransaction(); |
||
130 | $done = false; |
||
131 | |||
132 | if (empty($compare)) { |
||
133 | $compare = array_keys($input); |
||
134 | } |
||
135 | |||
136 | // Construct the update query |
||
137 | $qbu = $this->conn->getQueryBuilder(); |
||
138 | $qbu->update($table); |
||
139 | foreach($input as $col => $val) { |
||
140 | $qbu->set($col, $qbu->createParameter($col)) |
||
141 | ->setParameter($col, $val); |
||
142 | } |
||
143 | foreach($compare as $key) { |
||
144 | if (is_null($input[$key]) || ($input[$key] === '' && $this->conn->getDatabasePlatform() instanceof OraclePlatform)) { |
||
145 | $qbu->andWhere($qbu->expr()->isNull($key)); |
||
146 | } else { |
||
147 | if($this->conn->getDatabasePlatform() instanceof OraclePlatform) { |
||
148 | $qbu->andWhere( |
||
149 | $qbu->expr()->eq( |
||
150 | // needs to cast to char in order to compare with char |
||
151 | $qbu->createFunction('to_char(`'.$key.'`)'), // TODO does this handle empty strings on oracle correclty |
||
152 | $qbu->expr()->literal($input[$key]))); |
||
153 | } else { |
||
154 | $qbu->andWhere( |
||
155 | $qbu->expr()->eq( |
||
156 | $key, |
||
157 | $qbu->expr()->literal($input[$key]))); |
||
158 | } |
||
159 | } |
||
160 | } |
||
161 | |||
162 | // Construct the insert query |
||
163 | $qbi = $this->conn->getQueryBuilder(); |
||
164 | $qbi->insert($table); |
||
165 | foreach($input as $c => $v) { |
||
166 | $qbi->setValue($c, $qbi->createParameter($c)) |
||
167 | ->setParameter($c, $v); |
||
168 | } |
||
169 | |||
170 | $rows = 0; |
||
171 | $count = 0; |
||
172 | // Attempt 5 times before failing the upsert |
||
173 | $maxTry = 5; |
||
174 | |||
175 | while(!$done && $count < $maxTry) { |
||
176 | try { |
||
177 | // Try to update |
||
178 | $rows = $qbu->execute(); |
||
179 | } catch (DriverException $e) { |
||
180 | // Skip deadlock and retry |
||
181 | // @TODO when we update to DBAL 2.6 we can use DeadlockExceptions here |
||
182 | if($e->getErrorCode() == 1213) { |
||
183 | $count++; |
||
184 | continue; |
||
185 | } else { |
||
186 | // We should catch other exceptions up the stack |
||
187 | $this->conn->rollBack(); |
||
188 | throw $e; |
||
189 | } |
||
190 | } |
||
191 | if($rows > 0) { |
||
192 | // We altered some rows, return |
||
193 | $done = true; |
||
194 | } else { |
||
195 | // Try the insert |
||
196 | $this->conn->beginTransaction(); |
||
197 | try { |
||
198 | // Execute the insert query |
||
199 | $rows = $qbi->execute(); |
||
200 | $done = $rows > 0; |
||
201 | } catch (UniqueConstraintViolationException $e) { |
||
202 | // Catch the unique violation and try the loop again |
||
203 | $count++; |
||
204 | } |
||
205 | // Other exceptions are not caught, they should be caught up the stack |
||
206 | $this->conn->commit(); |
||
207 | } |
||
208 | } |
||
209 | |||
210 | // Pass through failures correctly |
||
211 | if($count === $maxTry) { |
||
212 | $params = implode(',', $input); |
||
213 | $updateQuery = $qbu->getSQL(); |
||
214 | $insertQuery = $qbi->getSQL(); |
||
215 | throw new \RuntimeException("DB upsert failed after $count attempts. UpdateQuery: $updateQuery InsertQuery: $insertQuery"); |
||
216 | } |
||
217 | |||
218 | $this->conn->commit(); |
||
219 | return $rows; |
||
220 | |||
221 | } |
||
222 | } |
||
223 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.