BuildFactory   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 65
Duplicated Lines 0 %

Coupling/Cohesion

Components 0
Dependencies 3

Test Coverage

Coverage 0%

Importance

Changes 5
Bugs 1 Features 0
Metric Value
wmc 11
c 5
b 1
f 0
lcom 0
cbo 3
dl 0
loc 65
ccs 0
cts 37
cp 0
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
A getBuildById() 0 10 2
D getBuild() 0 37 9
1
<?php
2
/**
3
* PHPCI - Continuous Integration for PHP.
4
*
5
* @copyright    Copyright 2014, Block 8 Limited.
6
* @license      https://github.com/Block8/PHPCI/blob/master/LICENSE.md
7
*
8
* @link         https://www.phptesting.org/
9
*/
10
11
namespace PHPCI;
12
13
use b8\Store\Factory;
14
use PHPCI\Model\Build;
15
16
/**
17
 * PHPCI Build Factory - Takes in a generic "Build" and returns a type-specific build model.
18
 *
19
 * @author   Dan Cryer <[email protected]>
20
 */
21
class BuildFactory
22
{
23
    /**
24
     * @param $buildId
25
     *
26
     * @return Build
27
     *
28
     * @throws \Exception
29
     */
30
    public static function getBuildById($buildId)
31
    {
32
        $build = Factory::getStore('Build')->getById($buildId);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class b8\Store as the method getById() does only exist in the following sub-classes of b8\Store: PHPCI\Store\Base\BuildErrorStoreBase, PHPCI\Store\Base\BuildMetaStoreBase, PHPCI\Store\Base\BuildStoreBase, PHPCI\Store\Base\ProjectGroupStoreBase, PHPCI\Store\Base\ProjectStoreBase, PHPCI\Store\Base\UserStoreBase, PHPCI\Store\BuildErrorStore, PHPCI\Store\BuildMetaStore, PHPCI\Store\BuildStore, PHPCI\Store\ProjectGroupStore, PHPCI\Store\ProjectStore, PHPCI\Store\UserStore. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

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

class MyUser extends 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 sub-classes 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 parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
33
34
        if (empty($build)) {
35
            throw new \Exception('Build ID '.$buildId.' does not exist.');
36
        }
37
38
        return self::getBuild($build);
39
    }
40
41
    /**
42
     * Takes a generic build and returns a type-specific build model.
43
     *
44
     * @param Build $build The build from which to get a more specific build type.
45
     *
46
     * @return Build
47
     */
48
    public static function getBuild(Build $build)
49
    {
50
        $project = $build->getProject();
51
52
        if (!empty($project)) {
53
            switch ($project->getType()) {
54
                case 'remote':
55
                    $type = 'RemoteGitBuild';
56
                    break;
57
                case 'local':
58
                    $type = 'LocalBuild';
59
                    break;
60
                case 'github':
61
                    $type = 'GithubBuild';
62
                    break;
63
                case 'bitbucket':
64
                    $type = 'BitbucketBuild';
65
                    break;
66
                case 'gitlab':
67
                    $type = 'GitlabBuild';
68
                    break;
69
                case 'hg':
70
                    $type = 'MercurialBuild';
71
                    break;
72
                case 'svn':
73
                    $type = 'SubversionBuild';
74
                    break;
75
                default:
76
                    return $build;
77
            }
78
79
            $class = '\\PHPCI\\Model\\Build\\'.$type;
80
            $build = new $class($build->getDataArray());
81
        }
82
83
        return $build;
84
    }
85
}
86