Failed Conditions
Push — master ( 598f4b...15edf4 )
by Alexander
04:31
created

RepositoryFiller::addPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 20
ccs 13
cts 13
cp 1
rs 9.4285
cc 1
eloc 12
nc 1
nop 4
crap 1
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 132
	public function __construct(ExtendedPdoInterface $database, DatabaseCache $database_cache)
42
	{
43 132
		$this->database = $database;
44 132
		$this->databaseCache = $database_cache;
45
46 132
		$this->databaseCache->cacheTable('Paths');
47 132
	}
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 54
	public function addProject($path, $is_deleted = 0, $bug_regexp = null)
59
	{
60
		$sql = 'INSERT INTO Projects (Path, IsDeleted, BugRegExp)
61 54
				VALUES (:path, :is_deleted, :bug_regexp)';
62 54
		$this->database->perform($sql, array(
63 54
			'path' => $path,
64 54
			'is_deleted' => $is_deleted,
65 54
			'bug_regexp' => $bug_regexp,
66 54
		));
67
68 54
		return $this->database->lastInsertId();
69
	}
70
71
	/**
72
	 * Changes project status.
73
	 *
74
	 * @param integer $project_id Project ID.
75
	 * @param integer $is_deleted Is deleted flag.
76
	 *
77
	 * @return void
78
	 */
79 7
	public function setProjectStatus($project_id, $is_deleted)
80
	{
81
		$sql = 'UPDATE Projects
82
				SET IsDeleted = :is_deleted
83 7
				WHERE Id = :id';
84 7
		$this->database->perform($sql, array(
85 7
			'is_deleted' => (int)$is_deleted,
86 7
			'id' => $project_id,
87 7
		));
88 7
	}
89
90
	/**
91
	 * Changes project bug regexp.
92
	 *
93
	 * @param integer     $project_id Project ID.
94
	 * @param string|null $bug_regexp Bug regexp.
95
	 *
96
	 * @return void
97
	 */
98 9
	public function setProjectBugRegexp($project_id, $bug_regexp)
99
	{
100
		$sql = 'UPDATE Projects
101
				SET BugRegExp = :bug_regexp
102 9
				WHERE Id = :id';
103 9
		$this->database->perform($sql, array(
104 9
			'bug_regexp' => $bug_regexp,
105 9
			'id' => $project_id,
106 9
		));
107 9
	}
108
109
	/**
110
	 * Adds commit.
111
	 *
112
	 * @param integer $revision Revision.
113
	 * @param string  $author   Author.
114
	 * @param integer $date     Date.
115
	 * @param string  $message  Message.
116
	 *
117
	 * @return void
118
	 */
119 50
	public function addCommit($revision, $author, $date, $message)
120
	{
121
		$sql = 'INSERT INTO Commits (Revision, Author, Date, Message)
122 50
				VALUES (:revision, :author, :date, :message)';
123 50
		$this->database->perform($sql, array(
124 50
			'revision' => $revision,
125 50
			'author' => $author,
126 50
			'date' => $date,
127 50
			'message' => $message,
128 50
		));
129 50
	}
130
131
	/**
132
	 * Adds commit to project.
133
	 *
134
	 * @param integer $revision   Revision.
135
	 * @param integer $project_id Project ID.
136
	 *
137
	 * @return void
138
	 */
139 46
	public function addCommitToProject($revision, $project_id)
140
	{
141
		$sql = 'INSERT INTO CommitProjects (ProjectId, Revision)
142 46
				VALUES (:project_id, :revision)';
143 46
		$this->database->perform($sql, array('project_id' => $project_id, 'revision' => $revision));
144 46
	}
145
146
	/**
147
	 * Adds path.
148
	 *
149
	 * @param string  $path         Path.
150
	 * @param string  $ref          Ref.
151
	 * @param string  $project_path Project path.
152
	 * @param integer $revision     Revision.
153
	 *
154
	 * @return integer
155
	 */
156 63
	public function addPath($path, $ref, $project_path, $revision)
157
	{
158
		$sql = 'INSERT INTO Paths (
159
					Path, PathNestingLevel, PathHash, RefName, ProjectPath, RevisionAdded, RevisionLastSeen
160
				)
161 63
				VALUES (:path, :path_nesting_level, :path_hash, :ref, :project_path, :revision, :revision)';
162 63
		$this->database->perform($sql, array(
163 63
			'path' => $path,
164 63
			'path_nesting_level' => substr_count($path, '/') - 1,
165 63
			'path_hash' => crc32($path),
166 63
			'ref' => $ref,
167 63
			'project_path' => $project_path,
168 63
			'revision' => $revision,
169 63
		));
170 63
		$path_id = $this->database->lastInsertId();
171
172 63
		$this->propagateRevisionLastSeen($path, $revision);
173
174 63
		return $path_id;
175
	}
176
177
	/**
178
	 * Adds path to commit.
179
	 *
180
	 * @param integer      $revision      Revision.
181
	 * @param string       $action        Action.
182
	 * @param string       $kind          Kind.
183
	 * @param integer      $path_id       Path ID.
184
	 * @param integer|null $copy_revision Copy revision.
185
	 * @param integer|null $copy_path_id  Copy path ID.
186
	 *
187
	 * @return void
188
	 */
189 58
	public function addPathToCommit($revision, $action, $kind, $path_id, $copy_revision = null, $copy_path_id = null)
190
	{
191
		$sql = 'INSERT INTO CommitPaths (Revision, Action, Kind, PathId, CopyRevision, CopyPathId)
192 58
				VALUES (:revision, :action, :kind, :path_id, :copy_revision, :copy_path_id)';
193 58
		$this->database->perform($sql, array(
194 58
			'revision' => $revision,
195 58
			'action' => $action,
196 58
			'kind' => $kind,
197 58
			'path_id' => $path_id,
198 58
			'copy_revision' => $copy_revision,
199 58
			'copy_path_id' => $copy_path_id,
200 58
		));
201 58
	}
202
203
	/**
204
	 * Touches given path.
205
	 *
206
	 * @param string  $path        Path.
207
	 * @param integer $revision    Revision.
208
	 * @param array   $fields_hash Fields hash.
209
	 *
210
	 * @return array
211
	 * @throws \InvalidArgumentException When "$fields_hash" is empty.
212
	 */
213 22
	public function touchPath($path, $revision, array $fields_hash)
214
	{
215 22
		if ( !$fields_hash ) {
216 1
			throw new \InvalidArgumentException('The "$fields_hash" variable can\'t be empty.');
217
		}
218
219 21
		$path_hash = crc32($path);
220 21
		$to_update = $this->propagateRevisionLastSeen($path, $revision);
221 21
		$to_update[$path_hash] = $fields_hash;
222
223 21
		$bind_params = array_values($fields_hash);
224 21
		$bind_params[] = $path_hash;
225
226
		$sql = 'UPDATE Paths
227 21
				SET ' . implode(' = ?, ', array_keys($fields_hash)) . ' = ?
228 21
				WHERE PathHash = ?';
229 21
		$this->database->perform($sql, $bind_params);
230
231 21
		return $to_update;
232
	}
233
234
	/**
235
	 * Propagates revision last seen.
236
	 *
237
	 * @param string $path     Path.
238
	 * @param string $revision Revision.
239
	 *
240
	 * @return array
241
	 */
242 63
	protected function propagateRevisionLastSeen($path, $revision)
243
	{
244 63
		$to_update = array();
245 63
		$update_path = $path;
246
247 63
		$select_sql = 'SELECT RevisionLastSeen FROM Paths WHERE PathHash = :path_hash';
248 63
		$update_sql = 'UPDATE Paths SET RevisionLastSeen = :revision WHERE PathHash = :path_hash';
249
250 63
		while ( ($update_path = dirname($update_path) . '/') !== '//' ) {
251 60
			$update_path_hash = crc32($update_path);
252
253 60
			$fields_hash = $this->databaseCache->getFromCache(
254 60
				'Paths',
255 60
				$update_path_hash . '/' . __METHOD__,
256 60
				$select_sql,
257 60
				array('path_hash' => $update_path_hash)
258 60
			);
259
260
			// Missing parent path. Can happen for example, when repository was created via "cvs2svn".
261 60
			if ( $fields_hash === false ) {
262
				/** @var StatementProfiler $profiler */
263 49
				$profiler = $this->database->getProfiler();
264 49
				$profiler->removeProfile($select_sql, array('path_hash' => $update_path_hash));
265 49
				break;
266
			}
267
268
			// TODO: Collect these paths and issue single update after cycle finishes.
269 20
			if ( (int)$fields_hash['RevisionLastSeen'] < $revision ) {
270 14
				$this->database->perform(
271 14
					$update_sql,
272 14
					array('revision' => $revision, 'path_hash' => $update_path_hash)
273 14
				);
274
275 14
				$fields_hash = array('RevisionLastSeen' => $revision);
276 14
				$this->databaseCache->setIntoCache('Paths', $update_path_hash . '/' . __METHOD__, $fields_hash);
277 14
				$to_update[$update_path_hash] = $fields_hash;
278 14
			}
279 20
		};
280
281 63
		return $to_update;
282
	}
283
284
	/**
285
	 * Returns fields, that needs to be changed for given path.
286
	 *
287
	 * @param string  $action    Action.
288
	 * @param integer $revision  Revision.
289
	 * @param array   $path_data Path data.
290
	 *
291
	 * @return array
292
	 */
293 27
	public function getPathTouchFields($action, $revision, array $path_data)
294
	{
295 27
		$fields_hash = array();
296
297 27
		if ( $action === 'D' ) {
298 6
			$fields_hash['RevisionDeleted'] = $revision;
299 6
		}
300
		else {
301 24
			if ( $path_data['RevisionDeleted'] > 0 ) {
302 4
				$fields_hash['RevisionDeleted'] = null;
303 4
			}
304
305 24
			if ( $action === 'A' && $path_data['RevisionAdded'] > $revision ) {
306 2
				$fields_hash['RevisionAdded'] = $revision;
307 2
			}
308
309 24
			if ( $path_data['RevisionLastSeen'] < $revision ) {
310 21
				$fields_hash['RevisionLastSeen'] = $revision;
311 21
			}
312
		}
313
314 27
		return $fields_hash;
315
	}
316
317
	/**
318
	 * Sets project path for given paths.
319
	 *
320
	 * @param array  $path_ids     Path IDs.
321
	 * @param string $project_path Project path.
322
	 *
323
	 * @return void
324
	 */
325 3
	public function movePathsIntoProject(array $path_ids, $project_path)
326
	{
327
		$sql = 'UPDATE Paths
328
				SET ProjectPath = :path
329 3
				WHERE Id IN (:path_ids)';
330 3
		$this->database->perform($sql, array(
331 3
			'path' => $project_path,
332 3
			'path_ids' => $path_ids,
333 3
		));
334 3
	}
335
336
	/**
337
	 * Adds commit with bugs.
338
	 *
339
	 * @param array   $bugs     Bugs.
340
	 * @param integer $revision Revision.
341
	 *
342
	 * @return void
343
	 */
344 42
	public function addBugsToCommit(array $bugs, $revision)
345
	{
346 42
		foreach ( $bugs as $bug ) {
347
			$sql = 'INSERT INTO CommitBugs (Revision, Bug)
348 8
					VALUES (:revision, :bug)';
349 8
			$this->database->perform($sql, array(
350 8
				'revision' => $revision,
351 8
				'bug' => $bug,
352 8
			));
353 42
		}
354 42
	}
355
356
	/**
357
	 * Adds merge commit.
358
	 *
359
	 * @param integer $revision         Revision.
360
	 * @param array   $merged_revisions Merged revisions.
361
	 *
362
	 * @return void
363
	 */
364 44
	public function addMergeCommit($revision, array $merged_revisions)
365
	{
366 44
		foreach ( $merged_revisions as $merged_revision ) {
367
			$sql = 'INSERT INTO Merges (MergeRevision, MergedRevision)
368 9
					VALUES (:merge_revision, :merged_revision)';
369 9
			$this->database->perform($sql, array(
370 9
				'merge_revision' => $revision,
371 9
				'merged_revision' => $merged_revision,
372 9
			));
373 44
		}
374 44
	}
375
376
	/**
377
	 * Adds ref to project.
378
	 *
379
	 * @param string  $ref        Ref.
380
	 * @param integer $project_id Project ID.
381
	 *
382
	 * @return integer
383
	 */
384 25
	public function addRefToProject($ref, $project_id)
385
	{
386
		$sql = 'INSERT INTO ProjectRefs (ProjectId, Name)
387 25
				VALUES (:project_id, :name)';
388 25
		$this->database->perform($sql, array('project_id' => $project_id, 'name' => $ref));
389
390 25
		return $this->database->lastInsertId();
391
	}
392
393
	/**
394
	 * Adds ref to commit and commit to project.
395
	 *
396
	 * @param integer $revision Revision.
397
	 * @param integer $ref_id   Ref ID.
398
	 *
399
	 * @return void
400
	 */
401 24
	public function addCommitToRef($revision, $ref_id)
402
	{
403
		$sql = 'INSERT INTO CommitRefs (Revision, RefId)
404 24
				VALUES (:revision, :ref_id)';
405 24
		$this->database->perform($sql, array('revision' => $revision, 'ref_id' => $ref_id));
406 24
	}
407
408
}
409