Completed
Push — master ( a6b26f...19dee2 )
by Andrii
03:13
created

StartController   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 202
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 57.38%

Importance

Changes 7
Bugs 1 Features 1
Metric Value
wmc 46
c 7
b 1
f 1
lcom 1
cbo 5
dl 0
loc 202
ccs 70
cts 122
cp 0.5738
rs 8.3999

14 Methods

Rating   Name   Duplication   Size   Complexity  
A actionMake() 0 15 2
A includeMainConfig() 0 4 1
A addAutoloader() 0 9 2
A actionUpdate() 0 4 1
B addAliases() 0 18 8
A hasAlias() 0 6 2
D requireAll() 0 25 9
C needsComposerInstall() 0 22 7
B includeAll() 0 13 5
A loadConfig() 0 7 2
A setRootDir() 0 4 1
A getRootDir() 0 8 2
A findRootDir() 0 11 3
A buildRootPath() 0 4 1

How to fix   Complexity   

Complex Class

Complex classes like StartController 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 StartController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * Automation tool mixed with code generator for easier continuous development
5
 *
6
 * @link      https://github.com/hiqdev/hidev
7
 * @package   hidev
8
 * @license   BSD-3-Clause
9
 * @copyright Copyright (c) 2015-2016, HiQDev (http://hiqdev.com/)
10
 */
11
12
namespace hidev\controllers;
13
14
use hidev\base\File;
15
use Yii;
16
use yii\base\InvalidParamException;
17
use yii\helpers\ArrayHelper;
18
19
/**
20
 * Start goal.
21
 * Chdirs to the project's root directory and loads dependencies and configs.
22
 */
23
class StartController extends CommonController
24
{
25
    /**
26
     * @var string absolute path to the project root directory
27
     */
28
    protected $_rootDir;
29
30
    /**
31
     * @var bool hidev already started flag
32
     */
33
    public static $started = false;
34
35
    /**
36
     * Make action.
37
     */
38 2
    public function actionMake()
39
    {
40 2
        self::$started = true;
41 2
        $this->getRootDir();
42 2
        $this->includeMainConfig();
43 2
        if (file_exists('.hidev/config-local.yml')) {
44
            $this->takeConfig()->includeConfig('.hidev/config-local.yml');
45
        }
46 2
        $this->addAliases();
47 2
        $this->addAutoloader();
48 2
        $this->requireAll();
49 2
        $this->includeAll();
50 2
        $this->loadConfig();
51 2
        $this->includeMainConfig();
52 2
    }
53
54 2
    public function includeMainConfig()
55
    {
56 2
        $this->takeConfig()->includeConfig('.hidev/config.yml');
57 2
    }
58
59 2
    public function addAutoloader()
60
    {
61 2
        $autoloader = Yii::getAlias('@root/vendor/autoload.php');
62 2
        if (file_exists($autoloader)) {
63
            spl_autoload_unregister(['Yii', 'autoload']);
64
            require $autoloader;
65
            spl_autoload_register(['Yii', 'autoload'], true, true);
66
        }
67 2
    }
68
69
    /**
70
     * Update action.
71
     * @return int exit code
72
     */
73
    public function actionUpdate()
74
    {
75
        return $this->passthru('composer', ['update', '-d', '.hidev', '--prefer-source', '--ansi']);
76
    }
77
78
    /**
79
     * Adds aliases:
80
     * - @root alias to current project root dir
81
     * - current package namespace for it could be used from hidev.
82
     */
83 2
    public function addAliases()
84
    {
85 2
        Yii::setAlias('@root', $this->getRootDir());
86 2
        $config = $this->takeConfig()->rawItem('package');
87 2
        $alias  = strtr($config['namespace'], '\\', '/');
88 2
        if ($alias && !Yii::getAlias('@' . $alias, false)) {
89
            $srcdir = Yii::getAlias('@root/' . ($config['src'] ?: 'src'));
90
            Yii::setAlias($alias, $srcdir);
0 ignored issues
show
Bug introduced by
It seems like $srcdir defined by \Yii::getAlias('@root/' ...onfig['src'] ?: 'src')) on line 89 can also be of type boolean; however, yii\BaseYii::setAlias() does only seem to accept string, 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...
91
        }
92 2
        $aliases = $this->takeConfig()->rawItem('aliases');
93 2
        if (!empty($aliases) && is_array($aliases)) {
94 2
            foreach ($aliases as $alias => $path) {
95 2
                if (!$this->hasAlias($alias)) {
96
                    Yii::setAlias($alias, $path);
97
                }
98 2
            }
99 2
        }
100 2
    }
101
102 2
    public function hasAlias($alias, $exact = true)
0 ignored issues
show
Unused Code introduced by
The parameter $exact is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
103
    {
104 2
        $pos = strpos($alias, '/');
105
106 2
        return $pos === false ? isset(Yii::$aliases[$alias]) : isset(Yii::$aliases[substr($alias, 0, $pos)][$alias]);
107
    }
108
109
    /**
110
     * Require all configured requires.
111
     */
112 2
    protected function requireAll()
113
    {
114 2
        $plugins = $this->takeConfig()->rawItem('plugins');
115 2
        $vendors = [];
116 2
        if ($plugins) {
117
            $file = File::create('.hidev/composer.json');
118
            $data = ArrayHelper::merge($file->load(), ['require' => $plugins]);
119
            if ($file->save($data) || !is_dir('.hidev/vendor')) {
120
                $this->runAction('update');
121
            }
122
            $vendors[] = '.hidev/vendor';
123 2
        } elseif ($this->needsComposerInstall()) {
124
            if ($this->passthru('composer', ['install', '--ansi'])) {
125
                throw new InvalidParamException('Failed initialize project with composer install');
126
            }
127
        }
128 2
        if (file_exists('vendor/hiqdev/config/hidev.php')) {
129
            $vendors[] = 'vendor';
130
        }
131 2
        if (!empty($vendors)) {
132
            foreach (array_unique($vendors) as $dir) {
133
                $this->module->loadExtraVendor($dir);
134
            }
135
        }
136 2
    }
137
138 2
    public function needsComposerInstall()
139
    {
140 2
        if (file_exists('vendor')) {
141
            return false;
142
        }
143 2
        if (!file_exists('composer.json')) {
144 2
            return false;
145
        }
146
        $data = File::create('composer.json')->load();
147
        foreach (['require', 'require-dev'] as $key) {
148
            if (isset($data[$key])) {
149
                foreach ($data[$key] as $package => $version) {
150
                    list(, $name) = explode('/', $package);
151
                    if (strncmp($name, 'hidev-', 6) === 0) {
152
                        return true;
153
                    }
154
                }
155
            }
156
        }
157
158
        return false;
159
    }
160
161
    /**
162
     * Include all configs.
163
     */
164 2
    public function includeAll()
165
    {
166 2
        $still = true;
167 2
        while ($still) {
168 2
            $still = false;
169 2
            $include = $this->takeConfig()->rawItem('include');
170 2
            if ($include) {
171
                foreach ($include as $path) {
172
                    $still = $still || $this->takeConfig()->includeConfig($path);
173
                }
174
            }
175 2
        }
176 2
    }
177
178
    /**
179
     * Load project's config if configured.
180
     */
181 2
    public function loadConfig()
182
    {
183 2
        $path = $this->takeConfig()->rawItem('config');
184 2
        if ($path) {
185 2
            $this->module->loadExtraConfig($path);
186 2
        }
187 2
    }
188
189
    public function setRootDir($value)
190
    {
191
        $this->_rootDir = $value;
192
    }
193
194 2
    public function getRootDir()
195
    {
196 2
        if ($this->_rootDir === null) {
197 2
            $this->_rootDir = $this->findRootDir();
198 2
        }
199
200 2
        return $this->_rootDir;
201
    }
202
203
    /**
204
     * Chdirs to project's root by looking for config file in the current directory and up.
205
     * @throws InvalidParamException when failed to find
206
     * @return string path to the root directory of hidev project
207
     */
208 2
    protected function findRootDir()
209
    {
210 2
        $configDir = '.hidev';
211 2
        for ($i = 0; $i < 9; ++$i) {
212 2
            if (is_dir($configDir)) {
213 2
                return getcwd();
214
            }
215
            chdir('..');
216
        }
217
        throw new InvalidParamException("Not a hidev project (or any of the parent directories).\nUse `hidev init` to initialize hidev project.");
218
    }
219
220
    public function buildRootPath($subpath)
221
    {
222
        return $this->getRootDir() . DIRECTORY_SEPARATOR . $subpath;
223
    }
224
}
225