Failed Conditions
Push — master ( dd969d...42da22 )
by Alexander
10:30
created

RepositoryFiller::addBugsToCommit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 8
ccs 6
cts 6
cp 1
rs 10
cc 2
nc 2
nop 2
crap 2
1
<?php
2
/**
3
 * This file is part of the SVN-Buddy library.
4
 * For the full copyright and license information, please view
5
 * the LICENSE file that was distributed with this source code.
6
 *
7
 * @copyright Alexander Obuhovich <[email protected]>
8
 * @link      https://github.com/console-helpers/svn-buddy
9
 */
10
11
namespace ConsoleHelpers\SVNBuddy\Repository\RevisionLog;
12
13
14
use Aura\Sql\ExtendedPdoInterface;
15
use ConsoleHelpers\SVNBuddy\Database\DatabaseCache;
16
use ConsoleHelpers\SVNBuddy\Database\StatementProfiler;
17
18
class RepositoryFiller
19
{
20
21
	/**
22
	 * Database.
23
	 *
24
	 * @var ExtendedPdoInterface
25
	 */
26
	protected $database;
27
28
	/**
29
	 * Database cache.
30
	 *
31
	 * @var DatabaseCache
32
	 */
33
	protected $databaseCache;
34
35
	/**
36
	 * RepositoryFiller constructor.
37
	 *
38
	 * @param ExtendedPdoInterface $database       Database.
39
	 * @param DatabaseCache        $database_cache Database cache.
40
	 */
41 149
	public function __construct(ExtendedPdoInterface $database, DatabaseCache $database_cache)
42
	{
43 149
		$this->database = $database;
44 149
		$this->databaseCache = $database_cache;
45
46 149
		$this->databaseCache->cacheTable('Paths');
47 149
	}
48
49
	/**
50
	 * Creates a project.
51
	 *
52
	 * @param string      $path       Path.
53
	 * @param integer     $is_deleted Is Deleted.
54
	 * @param string|null $bug_regexp Bug regexp.
55
	 *
56
	 * @return integer
57
	 */
58 71
	public function addProject($path, $is_deleted = 0, $bug_regexp = null)
59
	{
60 71
		$sql = 'INSERT INTO Projects (Path, IsDeleted, BugRegExp)
61
				VALUES (:path, :is_deleted, :bug_regexp)';
62 71
		$this->database->perform($sql, array(
63 71
			'path' => $path,
64 71
			'is_deleted' => $is_deleted,
65 71
			'bug_regexp' => $bug_regexp,
66
		));
67
68 71
		$project_id = $this->database->lastInsertId();
69
70
		// There are no "0" revision in repository, but we need to bind project path to some revision.
71 71
		if ( $path === '/' ) {
72 3
			$this->addPath($path, '', $path, 0);
73
		}
74
75 71
		return $project_id;
76
	}
77
78
	/**
79
	 * Changes project status.
80
	 *
81
	 * @param integer $project_id Project ID.
82
	 * @param integer $is_deleted Is deleted flag.
83
	 *
84
	 * @return void
85
	 */
86 9
	public function setProjectStatus($project_id, $is_deleted)
87
	{
88 9
		$sql = 'UPDATE Projects
89
				SET IsDeleted = :is_deleted
90
				WHERE Id = :id';
91 9
		$this->database->perform($sql, array(
92 9
			'is_deleted' => (int)$is_deleted,
93 9
			'id' => $project_id,
94
		));
95 9
	}
96
97
	/**
98
	 * Changes project bug regexp.
99
	 *
100
	 * @param integer     $project_id Project ID.
101
	 * @param string|null $bug_regexp Bug regexp.
102
	 *
103
	 * @return void
104
	 */
105 11
	public function setProjectBugRegexp($project_id, $bug_regexp)
106
	{
107 11
		$sql = 'UPDATE Projects
108
				SET BugRegExp = :bug_regexp
109
				WHERE Id = :id';
110 11
		$this->database->perform($sql, array(
111 11
			'bug_regexp' => $bug_regexp,
112 11
			'id' => $project_id,
113
		));
114 11
	}
115
116
	/**
117
	 * Adds commit.
118
	 *
119
	 * @param integer $revision Revision.
120
	 * @param string  $author   Author.
121
	 * @param integer $date     Date.
122
	 * @param string  $message  Message.
123
	 *
124
	 * @return void
125
	 */
126 65
	public function addCommit($revision, $author, $date, $message)
127
	{
128 65
		$sql = 'INSERT INTO Commits (Revision, Author, Date, Message)
129
				VALUES (:revision, :author, :date, :message)';
130 65
		$this->database->perform($sql, array(
131 65
			'revision' => $revision,
132 65
			'author' => $author,
133 65
			'date' => $date,
134 65
			'message' => $message,
135
		));
136 65
	}
137
138
	/**
139
	 * Adds commit to project.
140
	 *
141
	 * @param integer $revision   Revision.
142
	 * @param integer $project_id Project ID.
143
	 *
144
	 * @return void
145
	 */
146 61
	public function addCommitToProject($revision, $project_id)
147
	{
148 61
		$sql = 'INSERT INTO CommitProjects (ProjectId, Revision)
149
				VALUES (:project_id, :revision)';
150 61
		$this->database->perform($sql, array('project_id' => $project_id, 'revision' => $revision));
151 61
	}
152
153
	/**
154
	 * Adds path.
155
	 *
156
	 * @param string  $path         Path.
157
	 * @param string  $ref          Ref.
158
	 * @param string  $project_path Project path.
159
	 * @param integer $revision     Revision.
160
	 *
161
	 * @return integer
162
	 */
163 81
	public function addPath($path, $ref, $project_path, $revision)
164
	{
165 81
		$sql = 'INSERT INTO Paths (
166
					Path, PathNestingLevel, PathHash, RefName, ProjectPath, RevisionAdded, RevisionLastSeen
167
				)
168
				VALUES (:path, :path_nesting_level, :path_hash, :ref, :project_path, :revision, :revision)';
169 81
		$this->database->perform($sql, array(
170 81
			'path' => $path,
171 81
			'path_nesting_level' => substr_count($path, '/') - 1,
172 81
			'path_hash' => $this->getPathChecksum($path),
173 81
			'ref' => $ref,
174 81
			'project_path' => $project_path,
175 81
			'revision' => $revision,
176
		));
177 81
		$path_id = $this->database->lastInsertId();
178
179 81
		$this->propagateRevisionLastSeen($path, $revision);
180
181 81
		return $path_id;
182
	}
183
184
	/**
185
	 * Adds path to commit.
186
	 *
187
	 * @param integer      $revision      Revision.
188
	 * @param string       $action        Action.
189
	 * @param string       $kind          Kind.
190
	 * @param integer      $path_id       Path ID.
191
	 * @param integer|null $copy_revision Copy revision.
192
	 * @param integer|null $copy_path_id  Copy path ID.
193
	 *
194
	 * @return void
195
	 */
196 74
	public function addPathToCommit($revision, $action, $kind, $path_id, $copy_revision = null, $copy_path_id = null)
197
	{
198 74
		$sql = 'INSERT INTO CommitPaths (Revision, Action, Kind, PathId, CopyRevision, CopyPathId)
199
				VALUES (:revision, :action, :kind, :path_id, :copy_revision, :copy_path_id)';
200 74
		$this->database->perform($sql, array(
201 74
			'revision' => $revision,
202 74
			'action' => $action,
203 74
			'kind' => $kind,
204 74
			'path_id' => $path_id,
205 74
			'copy_revision' => $copy_revision,
206 74
			'copy_path_id' => $copy_path_id,
207
		));
208 74
	}
209
210
	/**
211
	 * Touches given path.
212
	 *
213
	 * @param string  $path        Path.
214
	 * @param integer $revision    Revision.
215
	 * @param array   $fields_hash Fields hash.
216
	 *
217
	 * @return array
218
	 * @throws \InvalidArgumentException When "$fields_hash" is empty.
219
	 */
220 35
	public function touchPath($path, $revision, array $fields_hash)
221
	{
222 35
		if ( !$fields_hash ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $fields_hash of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
223 1
			throw new \InvalidArgumentException('The "$fields_hash" variable can\'t be empty.');
224
		}
225
226 34
		$path_hash = $this->getPathChecksum($path);
227 34
		$to_update = $this->propagateRevisionLastSeen($path, $revision);
228 34
		$to_update[$path_hash] = $fields_hash;
229
230 34
		$bind_params = array_values($fields_hash);
231 34
		$bind_params[] = $path_hash;
232
233
		$sql = 'UPDATE Paths
234 34
				SET ' . implode(' = ?, ', array_keys($fields_hash)) . ' = ?
235
				WHERE PathHash = ?';
236 34
		$this->database->perform($sql, $bind_params);
237
238 34
		return $to_update;
239
	}
240
241
	/**
242
	 * Propagates revision last seen.
243
	 *
244
	 * @param string $path     Path.
245
	 * @param string $revision Revision.
246
	 *
247
	 * @return array
248
	 */
249 81
	protected function propagateRevisionLastSeen($path, $revision)
250
	{
251 81
		$to_update = array();
252 81
		$update_path = $path;
253
254 81
		$select_sql = 'SELECT RevisionLastSeen FROM Paths WHERE PathHash = :path_hash';
255 81
		$update_sql = 'UPDATE Paths SET RevisionLastSeen = :revision WHERE PathHash = :path_hash';
256
257 81
		while ( ($update_path = dirname($update_path) . '/') !== '//' ) {
258 76
			$update_path_hash = $this->getPathChecksum($update_path);
259
260 76
			$fields_hash = $this->databaseCache->getFromCache(
261 76
				'Paths',
262 76
				$update_path_hash . '/' . __METHOD__,
263
				$select_sql,
264 76
				array('path_hash' => $update_path_hash)
265
			);
266
267
			// Missing parent path. Can happen for example, when repository was created via "cvs2svn".
268 76
			if ( $fields_hash === false ) {
269 52
				$profiler = $this->database->getProfiler();
270
271 52
				if ( $profiler instanceof StatementProfiler ) {
272 12
					$profiler->removeProfile($select_sql, array('path_hash' => $update_path_hash));
273
				}
274 52
				break;
275
			}
276
277
			// TODO: Collect these paths and issue single update after cycle finishes.
278 37
			if ( (int)$fields_hash['RevisionLastSeen'] < $revision ) {
279 30
				$this->database->perform(
280 30
					$update_sql,
281 30
					array('revision' => $revision, 'path_hash' => $update_path_hash)
282
				);
283
284 30
				$fields_hash = array('RevisionLastSeen' => $revision);
285 30
				$this->databaseCache->setIntoCache('Paths', $update_path_hash . '/' . __METHOD__, $fields_hash);
286 30
				$to_update[$update_path_hash] = $fields_hash;
287
			}
288
		};
289
290 81
		return $to_update;
291
	}
292
293
	/**
294
	 * Returns fields, that needs to be changed for given path.
295
	 *
296
	 * @param string  $action    Action.
297
	 * @param integer $revision  Revision.
298
	 * @param array   $path_data Path data.
299
	 *
300
	 * @return array
301
	 */
302 40
	public function getPathTouchFields($action, $revision, array $path_data)
303
	{
304 40
		$fields_hash = array();
305
306 40
		if ( $action === 'D' ) {
307 6
			$fields_hash['RevisionDeleted'] = $revision;
308
		}
309
		else {
310 37
			if ( $path_data['RevisionDeleted'] > 0 ) {
311 4
				$fields_hash['RevisionDeleted'] = null;
312
			}
313
314 37
			if ( $action === 'A' && $path_data['RevisionAdded'] > $revision ) {
315 2
				$fields_hash['RevisionAdded'] = $revision;
316
			}
317
318 37
			if ( $path_data['RevisionLastSeen'] < $revision ) {
319 34
				$fields_hash['RevisionLastSeen'] = $revision;
320
			}
321
		}
322
323 40
		return $fields_hash;
324
	}
325
326
	/**
327
	 * Sets project path for given paths.
328
	 *
329
	 * @param array  $path_ids     Path IDs.
330
	 * @param string $project_path Project path.
331
	 *
332
	 * @return void
333
	 */
334 4
	public function movePathsIntoProject(array $path_ids, $project_path)
335
	{
336 4
		$sql = 'UPDATE Paths
337
				SET ProjectPath = :path
338
				WHERE Id IN (:path_ids)';
339 4
		$this->database->perform($sql, array(
340 4
			'path' => $project_path,
341 4
			'path_ids' => $path_ids,
342
		));
343 4
	}
344
345
	/**
346
	 * Adds commit with bugs.
347
	 *
348
	 * @param array   $bugs     Bugs.
349
	 * @param integer $revision Revision.
350
	 *
351
	 * @return void
352
	 */
353 57
	public function addBugsToCommit(array $bugs, $revision)
354
	{
355 57
		foreach ( $bugs as $bug ) {
356 8
			$sql = 'INSERT INTO CommitBugs (Revision, Bug)
357
					VALUES (:revision, :bug)';
358 8
			$this->database->perform($sql, array(
359 8
				'revision' => $revision,
360 8
				'bug' => $bug,
361
			));
362
		}
363 57
	}
364
365
	/**
366
	 * Adds merge commit.
367
	 *
368
	 * @param integer $revision         Revision.
369
	 * @param array   $merged_revisions Merged revisions.
370
	 *
371
	 * @return void
372
	 */
373 59
	public function addMergeCommit($revision, array $merged_revisions)
374
	{
375 59
		foreach ( $merged_revisions as $merged_revision ) {
376 9
			$sql = 'INSERT INTO Merges (MergeRevision, MergedRevision)
377
					VALUES (:merge_revision, :merged_revision)';
378 9
			$this->database->perform($sql, array(
379 9
				'merge_revision' => $revision,
380 9
				'merged_revision' => $merged_revision,
381
			));
382
		}
383 59
	}
384
385
	/**
386
	 * Adds ref to project.
387
	 *
388
	 * @param string  $ref        Ref.
389
	 * @param integer $project_id Project ID.
390
	 *
391
	 * @return integer
392
	 */
393 39
	public function addRefToProject($ref, $project_id)
394
	{
395 39
		$sql = 'INSERT INTO ProjectRefs (ProjectId, Name)
396
				VALUES (:project_id, :name)';
397 39
		$this->database->perform($sql, array('project_id' => $project_id, 'name' => $ref));
398
399 39
		return $this->database->lastInsertId();
400
	}
401
402
	/**
403
	 * Adds ref to commit and commit to project.
404
	 *
405
	 * @param integer $revision Revision.
406
	 * @param integer $ref_id   Ref ID.
407
	 *
408
	 * @return void
409
	 */
410 38
	public function addCommitToRef($revision, $ref_id)
411
	{
412 38
		$sql = 'INSERT INTO CommitRefs (Revision, RefId)
413
				VALUES (:revision, :ref_id)';
414 38
		$this->database->perform($sql, array('revision' => $revision, 'ref_id' => $ref_id));
415 38
	}
416
417
	/**
418
	 * Returns unsigned checksum of the path.
419
	 *
420
	 * @param string $path Path.
421
	 *
422
	 * @return integer
423
	 */
424 81
	public function getPathChecksum($path)
425
	{
426 81
		return sprintf('%u', crc32($path));
0 ignored issues
show
Bug Best Practice introduced by
The expression return sprintf('%u', crc32($path)) returns the type string which is incompatible with the documented return type integer.
Loading history...
427
	}
428
429
}
430