Failed Conditions
Push — master ( d32373...a3f91c )
by Alexander
01:43
created

RevisionLog   B

Complexity

Total Complexity 47

Size/Duplication

Total Lines 452
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 97.79%

Importance

Changes 0
Metric Value
wmc 47
lcom 1
cbo 5
dl 0
loc 452
ccs 133
cts 136
cp 0.9779
rs 8.64
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 14 1
A refresh() 0 23 4
A _databaseReady() 0 6 2
A _getAggregateRevision() 0 14 3
C _queryRevisionData() 0 67 10
A _getLogCommandArguments() 0 18 3
A _getRevisionQueryFlags() 0 10 2
A _parseLog() 0 6 2
A _displayPluginActivityStatistics() 0 16 3
A registerPlugin() 0 11 2
A find() 0 4 1
A getRevisionsData() 0 4 1
A pluginRegistered() 0 4 1
A getPlugin() 0 8 2
A getBugsFromRevisions() 0 15 3
A getRepositoryCollectorPlugins() 0 6 1
A getDatabaseCollectorPlugins() 0 6 1
A getPluginsByInterface() 0 12 3
A getProjectPath() 0 4 1
A getRefName() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like RevisionLog often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RevisionLog, and based on these observations, apply Extract Interface, too.

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 ConsoleHelpers\ConsoleKit\ConsoleIO;
15
use ConsoleHelpers\SVNBuddy\Repository\Connector\Connector;
16
use ConsoleHelpers\SVNBuddy\Repository\RevisionLog\Plugin\IDatabaseCollectorPlugin;
17
use ConsoleHelpers\SVNBuddy\Repository\RevisionLog\Plugin\IPlugin;
18
use ConsoleHelpers\SVNBuddy\Repository\RevisionLog\Plugin\IRepositoryCollectorPlugin;
19
20
class RevisionLog
21
{
22
23
	const FLAG_VERBOSE = 1;
24
25
	const FLAG_MERGE_HISTORY = 2;
26
27
	/**
28
	 * Repository path.
29
	 *
30
	 * @var string
31
	 */
32
	private $_repositoryRootUrl;
33
34
	/**
35
	 * Project path.
36
	 *
37
	 * @var string
38
	 */
39
	private $_projectPath;
40
41
	/**
42
	 * Ref name.
43
	 *
44
	 * @var string
45
	 */
46
	private $_refName;
47
48
	/**
49
	 * Repository connector.
50
	 *
51
	 * @var Connector
52
	 */
53
	private $_repositoryConnector;
54
55
	/**
56
	 * Console IO.
57
	 *
58
	 * @var ConsoleIO
59
	 */
60
	private $_io;
61
62
	/**
63
	 * Installed plugins.
64
	 *
65
	 * @var IPlugin[]
66
	 */
67
	private $_plugins = array();
68
69
	/**
70
	 * Create revision log.
71
	 *
72
	 * @param string    $repository_url       Repository url.
73
	 * @param Connector $repository_connector Repository connector.
74
	 * @param ConsoleIO $io                   Console IO.
75
	 */
76 18
	public function __construct(
77
		$repository_url,
78
		Connector $repository_connector,
79
		ConsoleIO $io = null
80
	) {
81 18
		$this->_io = $io;
82 18
		$this->_repositoryConnector = $repository_connector;
83
84 18
		$this->_repositoryRootUrl = $repository_connector->getRootUrl($repository_url);
85
86 18
		$relative_path = $repository_connector->getRelativePath($repository_url);
87 18
		$this->_projectPath = $repository_connector->getProjectUrl($relative_path) . '/';
88 18
		$this->_refName = $repository_connector->getRefByPath($relative_path);
0 ignored issues
show
Documentation Bug introduced by
It seems like $repository_connector->g...fByPath($relative_path) can also be of type false. However, the property $_refName is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
89 18
	}
90
91
	/**
92
	 * Queries missing revisions.
93
	 *
94
	 * @param boolean $is_migration Is migration.
95
	 *
96
	 * @return void
97
	 * @throws \LogicException When no plugins are registered.
98
	 */
99 6
	public function refresh($is_migration)
100
	{
101 6
		if ( !$this->_plugins ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->_plugins of type ConsoleHelpers\SVNBuddy\...ionLog\Plugin\IPlugin[] 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...
102 1
			throw new \LogicException('Please register at least one revision log plugin.');
103
		}
104
105 5
		$this->_databaseReady();
106
107 5
		if ( $is_migration ) {
108
			// Import missing data for imported commits only.
109
			$from_revision = 0;
110
			$to_revision = $this->_getAggregateRevision('max');
111
		}
112
		else {
113
			// Import all data for new commits only.
114 5
			$from_revision = $this->_getAggregateRevision('min');
115 5
			$to_revision = $this->_repositoryConnector->getLastRevision($this->_repositoryRootUrl);
116
		}
117
118 5
		if ( $to_revision > $from_revision ) {
119 3
			$this->_queryRevisionData($from_revision, $to_revision);
120
		}
121 5
	}
122
123
	/**
124
	 * Reports to each plugin, that database is ready for usage.
125
	 *
126
	 * @return void
127
	 */
128 5
	private function _databaseReady()
129
	{
130 5
		foreach ( $this->_plugins as $plugin ) {
131 5
			$plugin->whenDatabaseReady();
132
		}
133 5
	}
134
135
	/**
136
	 * Returns aggregated revision from all plugins.
137
	 *
138
	 * @param string $function Aggregate function.
139
	 *
140
	 * @return integer
141
	 */
142 5
	private function _getAggregateRevision($function)
143
	{
144 5
		$last_revisions = array();
145
146 5
		foreach ( $this->_plugins as $plugin ) {
147 5
			$last_revisions[] = $plugin->getLastRevision();
148
		}
149
150 5
		if ( count($last_revisions) > 1 ) {
151 5
			return call_user_func_array($function, $last_revisions);
152
		}
153
154
		return current($last_revisions);
155
	}
156
157
	/**
158
	 * Queries missing revision data.
159
	 *
160
	 * @param integer $from_revision From revision.
161
	 * @param integer $to_revision   To revision.
162
	 *
163
	 * @return void
164
	 */
165 3
	private function _queryRevisionData($from_revision, $to_revision)
166
	{
167 3
		$range_start = $from_revision;
168
169
		// The "io" isn't set during autocomplete.
170 3
		if ( isset($this->_io) ) {
171
			// Create progress bar for repository plugins, where data amount is known upfront.
172 2
			$progress_bar = $this->_io->createProgressBar(ceil(($to_revision - $from_revision) / 200) + 1);
173 2
			$progress_bar->setMessage(' * Reading missing revisions:');
174 2
			$progress_bar->setFormat(
175 2
				'%message% %current%/%max% [%bar%] <info>%percent:3s%%</info> %elapsed:6s%/%estimated:-6s% <info>%memory:-10s%</info>'
176
			);
177 2
			$progress_bar->start();
178
		}
179
180 3
		$log_command_arguments = $this->_getLogCommandArguments();
181 3
		$is_verbose = isset($this->_io) && $this->_io->isVerbose();
182
183 3
		while ( $range_start <= $to_revision ) {
184 3
			$range_end = min($range_start + 199, $to_revision);
185
186 3
			$command = $this->_repositoryConnector->getCommand(
187 3
				'log',
188 3
				sprintf($log_command_arguments, $range_start, $range_end, $this->_repositoryRootUrl)
189
			);
190 3
			$command->setCacheDuration('10 years');
191 3
			$svn_log = $command->run();
192
193 3
			$this->_parseLog($svn_log);
0 ignored issues
show
Bug introduced by
It seems like $svn_log defined by $command->run() on line 191 can also be of type string; however, ConsoleHelpers\SVNBuddy\...evisionLog::_parseLog() does only seem to accept object<SimpleXMLElement>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
194
195 3
			$range_start = $range_end + 1;
196
197 3
			if ( isset($progress_bar) ) {
198 2
				$progress_bar->advance();
199
			}
200
		}
201
202 3
		if ( isset($progress_bar) ) {
203
			// Remove progress bar of repository plugins.
204 2
			$progress_bar->clear();
205 2
			unset($progress_bar);
206
207
			// Create progress bar for database plugins, where data amount isn't known upfront.
208 2
			$progress_bar = $this->_io->createProgressBar();
209 2
			$progress_bar->setMessage(' * Reading missing revisions:');
210 2
			$progress_bar->setFormat('%message% %current% [%bar%] %elapsed:6s% <info>%memory:-10s%</info>');
211 2
			$progress_bar->start();
212
213 2
			foreach ( $this->getDatabaseCollectorPlugins() as $plugin ) {
214 2
				$plugin->process($from_revision, $to_revision, $progress_bar);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface ConsoleHelpers\SVNBuddy\...isionLog\Plugin\IPlugin as the method process() does only exist in the following implementations of said interface: ConsoleHelpers\SVNBuddy\...DatabaseCollectorPlugin, ConsoleHelpers\SVNBuddy\...onLog\Plugin\BugsPlugin, ConsoleHelpers\SVNBuddy\...g\Plugin\ProjectsPlugin, ConsoleHelpers\SVNBuddy\...onLog\Plugin\RefsPlugin.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
215
			}
216
		}
217
		else {
218 1
			foreach ( $this->getDatabaseCollectorPlugins() as $plugin ) {
219 1
				$plugin->process($from_revision, $to_revision);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface ConsoleHelpers\SVNBuddy\...isionLog\Plugin\IPlugin as the method process() does only exist in the following implementations of said interface: ConsoleHelpers\SVNBuddy\...DatabaseCollectorPlugin, ConsoleHelpers\SVNBuddy\...onLog\Plugin\BugsPlugin, ConsoleHelpers\SVNBuddy\...g\Plugin\ProjectsPlugin, ConsoleHelpers\SVNBuddy\...onLog\Plugin\RefsPlugin.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
220
			}
221
		}
222
223 3
		if ( isset($progress_bar) ) {
224 2
			$progress_bar->finish();
225 2
			$this->_io->writeln('');
226
		}
227
228 3
		if ( $is_verbose ) {
229 1
			$this->_displayPluginActivityStatistics();
230
		}
231 3
	}
232
233
	/**
234
	 * Returns arguments for "log" command.
235
	 *
236
	 * @return string
237
	 */
238 3
	private function _getLogCommandArguments()
239
	{
240 3
		$query_flags = $this->_getRevisionQueryFlags();
241
242 3
		$ret = '-r %d:%d --xml';
243
244 3
		if ( in_array(self::FLAG_VERBOSE, $query_flags) ) {
245 3
			$ret .= ' --verbose';
246
		}
247
248 3
		if ( in_array(self::FLAG_MERGE_HISTORY, $query_flags) ) {
249 3
			$ret .= ' --use-merge-history';
250
		}
251
252 3
		$ret .= ' {%s}';
253
254 3
		return $ret;
255
	}
256
257
	/**
258
	 * Returns revision query flags.
259
	 *
260
	 * @return array
261
	 */
262 3
	private function _getRevisionQueryFlags()
263
	{
264 3
		$ret = array();
265
266 3
		foreach ( $this->getRepositoryCollectorPlugins() as $plugin ) {
267 3
			$ret = array_merge($ret, $plugin->getRevisionQueryFlags());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface ConsoleHelpers\SVNBuddy\...isionLog\Plugin\IPlugin as the method getRevisionQueryFlags() does only exist in the following implementations of said interface: ConsoleHelpers\SVNBuddy\...positoryCollectorPlugin, ConsoleHelpers\SVNBuddy\...Log\Plugin\MergesPlugin, ConsoleHelpers\SVNBuddy\...nLog\Plugin\PathsPlugin, ConsoleHelpers\SVNBuddy\...og\Plugin\SummaryPlugin.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
268
		}
269
270 3
		return array_unique($ret);
271
	}
272
273
	/**
274
	 * Parses output of "svn log" command.
275
	 *
276
	 * @param \SimpleXMLElement $log Log.
277
	 *
278
	 * @return void
279
	 */
280 3
	private function _parseLog(\SimpleXMLElement $log)
281
	{
282 3
		foreach ( $this->getRepositoryCollectorPlugins() as $plugin ) {
283 3
			$plugin->parse($log);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface ConsoleHelpers\SVNBuddy\...isionLog\Plugin\IPlugin as the method parse() does only exist in the following implementations of said interface: ConsoleHelpers\SVNBuddy\...positoryCollectorPlugin, ConsoleHelpers\SVNBuddy\...Log\Plugin\MergesPlugin, ConsoleHelpers\SVNBuddy\...nLog\Plugin\PathsPlugin, ConsoleHelpers\SVNBuddy\...og\Plugin\SummaryPlugin.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
284
		}
285 3
	}
286
287
	/**
288
	 * Displays plugin activity statistics.
289
	 *
290
	 * @return void
291
	 */
292 1
	private function _displayPluginActivityStatistics()
293
	{
294 1
		$statistics = array();
295
296
		// Combine statistics from all plugins.
297 1
		foreach ( $this->_plugins as $plugin ) {
298 1
			$statistics = array_merge($statistics, array_filter($plugin->getStatistics()));
299
		}
300
301
		// Show statistics.
302 1
		$this->_io->writeln('<debug>Combined Plugin Statistics:</debug>');
303
304 1
		foreach ( $statistics as $statistic_type => $occurrences ) {
305 1
			$this->_io->writeln('<debug> * ' . $statistic_type . ': ' . $occurrences . '</debug>');
306
		}
307 1
	}
308
309
	/**
310
	 * Registers a plugin.
311
	 *
312
	 * @param IPlugin $plugin Plugin.
313
	 *
314
	 * @return void
315
	 * @throws \LogicException When plugin is registered several times.
316
	 */
317 12
	public function registerPlugin(IPlugin $plugin)
318
	{
319 12
		$plugin_name = $plugin->getName();
320
321 12
		if ( $this->pluginRegistered($plugin_name) ) {
322 1
			throw new \LogicException('The "' . $plugin_name . '" revision log plugin is already registered.');
323
		}
324
325 12
		$plugin->setRevisionLog($this);
326 12
		$this->_plugins[$plugin_name] = $plugin;
327 12
	}
328
329
	/**
330
	 * Finds information using plugin.
331
	 *
332
	 * @param string       $plugin_name Plugin name.
333
	 * @param array|string $criteria    Search criteria.
334
	 *
335
	 * @return array
336
	 */
337 3
	public function find($plugin_name, $criteria)
338
	{
339 3
		return $this->getPlugin($plugin_name)->find((array)$criteria, $this->_projectPath);
340
	}
341
342
	/**
343
	 * Returns information about revisions.
344
	 *
345
	 * @param string $plugin_name Plugin name.
346
	 * @param array  $revisions   Revisions.
347
	 *
348
	 * @return array
349
	 */
350 3
	public function getRevisionsData($plugin_name, array $revisions)
351
	{
352 3
		return $this->getPlugin($plugin_name)->getRevisionsData($revisions);
353
	}
354
355
	/**
356
	 * Determines if plugin is registered.
357
	 *
358
	 * @param string $plugin_name Plugin name.
359
	 *
360
	 * @return boolean
361
	 */
362 15
	public function pluginRegistered($plugin_name)
363
	{
364 15
		return array_key_exists($plugin_name, $this->_plugins);
365
	}
366
367
	/**
368
	 * Returns plugin instance.
369
	 *
370
	 * @param string $plugin_name Plugin name.
371
	 *
372
	 * @return IPlugin
373
	 * @throws \InvalidArgumentException When unknown plugin is given.
374
	 */
375 8
	public function getPlugin($plugin_name)
376
	{
377 8
		if ( !$this->pluginRegistered($plugin_name) ) {
378 3
			throw new \InvalidArgumentException('The "' . $plugin_name . '" revision log plugin is unknown.');
379
		}
380
381 5
		return $this->_plugins[$plugin_name];
382
	}
383
384
	/**
385
	 * Returns bugs, from revisions.
386
	 *
387
	 * @param array $revisions Revisions.
388
	 *
389
	 * @return array
390
	 */
391 1
	public function getBugsFromRevisions(array $revisions)
392
	{
393 1
		$bugs = array();
394 1
		$revisions_bugs = $this->getRevisionsData('bugs', $revisions);
395
396 1
		foreach ( $revisions as $revision ) {
397 1
			$revision_bugs = $revisions_bugs[$revision];
398
399 1
			foreach ( $revision_bugs as $bug_id ) {
400 1
				$bugs[$bug_id] = true;
401
			}
402
		}
403
404 1
		return array_keys($bugs);
405
	}
406
407
	/**
408
	 * Returns repository collector plugins.
409
	 *
410
	 * @return IRepositoryCollectorPlugin[]
411
	 */
412 3
	protected function getRepositoryCollectorPlugins()
413
	{
414 3
		return $this->getPluginsByInterface(
415 3
			'ConsoleHelpers\SVNBuddy\Repository\RevisionLog\Plugin\IRepositoryCollectorPlugin'
416
		);
417
	}
418
419
	/**
420
	 * Returns database collector plugins.
421
	 *
422
	 * @return IDatabaseCollectorPlugin[]
423
	 */
424 3
	protected function getDatabaseCollectorPlugins()
425
	{
426 3
		return $this->getPluginsByInterface(
427 3
			'ConsoleHelpers\SVNBuddy\Repository\RevisionLog\Plugin\IDatabaseCollectorPlugin'
428
		);
429
	}
430
431
	/**
432
	 * Returns plugin list filtered by interface.
433
	 *
434
	 * @param string $interface Interface name.
435
	 *
436
	 * @return IPlugin[]
437
	 */
438 3
	protected function getPluginsByInterface($interface)
439
	{
440 3
		$ret = array();
441
442 3
		foreach ( $this->_plugins as $plugin ) {
443 3
			if ( $plugin instanceof $interface ) {
444 3
				$ret[] = $plugin;
445
			}
446
		}
447
448 3
		return $ret;
449
	}
450
451
	/**
452
	 * Returns project path.
453
	 *
454
	 * @return string
455
	 */
456 1
	public function getProjectPath()
457
	{
458 1
		return $this->_projectPath;
459
	}
460
461
	/**
462
	 * Returns ref name.
463
	 *
464
	 * @return string
465
	 */
466 1
	public function getRefName()
467
	{
468 1
		return $this->_refName;
469
	}
470
471
}
472