Completed
Push — master ( 897567...887f9d )
by Andrii
03:40
created

StartController   B

Complexity

Total Complexity 48

Size/Duplication

Total Lines 204
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 68.42%

Importance

Changes 6
Bugs 2 Features 0
Metric Value
wmc 48
lcom 1
cbo 5
dl 0
loc 204
ccs 65
cts 95
cp 0.6842
rs 8.4864
c 6
b 2
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A setRootDir() 0 4 1
A buildRootPath() 0 4 1
A includeMainConfig() 0 7 2
A addAutoloader() 0 9 2
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 getRootDir() 0 8 2
A findRootDir() 0 11 3
A actionMake() 0 12 1
A actionUpdate() 0 6 2
B addAliases() 0 18 9

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
 * Automation tool mixed with code generator for easier continuous development.
4
 *
5
 * @link      https://github.com/hiqdev/hidev
6
 * @package   hidev
7
 * @license   BSD-3-Clause
8
 * @copyright Copyright (c) 2015-2017, HiQDev (http://hiqdev.com/)
9
 */
10
11
namespace hidev\controllers;
12
13
use hidev\base\File;
14
use Yii;
15
use yii\base\InvalidParamException;
16
use yii\helpers\ArrayHelper;
17
18
/**
19
 * Start goal.
20
 * Chdirs to the project's root directory and loads dependencies and configs.
21
 */
22
class StartController extends CommonController
23
{
24
    /**
25
     * @var string absolute path to the project root directory
26
     */
27
    protected $_rootDir;
28
29
    /**
30
     * @var bool hidev already started flag
31
     */
32
    public static $started = false;
33
34
    /**
35
     * Make action.
36
     */
37 2
    public function actionMake()
38
    {
39 2
        self::$started = true;
40 2
        $this->getRootDir();
41 2
        $this->includeMainConfig();
42 2
        $this->addAliases();
43 2
        $this->addAutoloader();
44 2
        $this->requireAll();
45 2
        $this->includeAll();
46 2
        $this->loadConfig();
47 2
        $this->includeMainConfig();
48 2
    }
49
50 2
    public function includeMainConfig()
51
    {
52 2
        $this->takeConfig()->includeConfig('.hidev/config.yml');
53 2
        if (file_exists('.hidev/config-local.yml')) {
54
            $this->takeConfig()->includeConfig('.hidev/config-local.yml');
55
        }
56 2
    }
57
58 2
    public function addAutoloader()
59
    {
60 2
        $autoloader = Yii::getAlias('@root/vendor/autoload.php');
61 2
        if (file_exists($autoloader)) {
62
            spl_autoload_unregister(['Yii', 'autoload']);
63
            require $autoloader;
64
            spl_autoload_register(['Yii', 'autoload'], true, true);
65
        }
66 2
    }
67
68
    /**
69
     * Update action.
70
     * @return int exit code
71
     */
72
    public function actionUpdate()
73
    {
74
        if (file_exists('.hidev/composer.json')) {
75
            return $this->passthru('composer', ['update', '-d', '.hidev', '--prefer-source', '--ansi']);
76
        }
77
    }
78
79
    /**
80
     * Adds aliases:
81
     * - @root alias to current project root dir
82
     * - current package namespace for it could be used from hidev.
83
     */
84 2
    public function addAliases()
85
    {
86 2
        Yii::setAlias('@root', $this->getRootDir());
87 2
        $config = $this->takeConfig()->rawItem('package');
88 2
        $alias  = isset($config['namespace']) ? strtr($config['namespace'], '\\', '/') : '';
89 2
        if ($alias && !Yii::getAlias('@' . $alias, false)) {
90
            $srcdir = Yii::getAlias('@root/' . ($config['src'] ?: 'src'));
91
            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 90 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...
92
        }
93 2
        $aliases = $this->takeConfig()->rawItem('aliases');
94 2
        if (!empty($aliases) && is_array($aliases)) {
95 2
            foreach ($aliases as $alias => $path) {
96 2
                if (!$this->hasAlias($alias)) {
97
                    Yii::setAlias($alias, $path);
98
                }
99
            }
100
        }
101 2
    }
102
103 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...
104
    {
105 2
        $pos = strpos($alias, '/');
106
107 2
        return $pos === false ? isset(Yii::$aliases[$alias]) : isset(Yii::$aliases[substr($alias, 0, $pos)][$alias]);
108
    }
109
110
    /**
111
     * Require all configured requires.
112
     */
113 2
    protected function requireAll()
114
    {
115 2
        $plugins = $this->takeConfig()->rawItem('plugins');
116 2
        $vendors = [];
117 2
        if ($plugins) {
118
            $file = File::create('.hidev/composer.json');
119
            $data = ArrayHelper::merge($file->load(), ['require' => $plugins]);
120
            if ($file->save($data) || !is_dir('.hidev/vendor')) {
121
                $this->runAction('update');
122
            }
123
            $vendors[] = '.hidev/vendor';
124 2
        } elseif ($this->needsComposerInstall()) {
125
            if ($this->passthru('composer', ['install', '--ansi'])) {
126
                throw new InvalidParamException('Failed initialize project with composer install');
127
            }
128
        }
129 2
        if (file_exists('vendor/hiqdev/composer-config-plugin-output/hidev.php')) {
130
            $vendors[] = 'vendor';
131
        }
132 2
        if (!empty($vendors)) {
133
            foreach (array_unique($vendors) as $dir) {
134
                $this->module->loadExtraVendor($dir);
135
            }
136
        }
137 2
    }
138
139 2
    public function needsComposerInstall()
140
    {
141 2
        if (file_exists('vendor')) {
142
            return false;
143
        }
144 2
        if (!file_exists('composer.json')) {
145 2
            return false;
146
        }
147
        $data = File::create('composer.json')->load();
148
        foreach (['require', 'require-dev'] as $key) {
149
            if (isset($data[$key])) {
150
                foreach ($data[$key] as $package => $version) {
151
                    list(, $name) = explode('/', $package);
152
                    if (strncmp($name, 'hidev-', 6) === 0) {
153
                        return true;
154
                    }
155
                }
156
            }
157
        }
158
159
        return false;
160
    }
161
162
    /**
163
     * Include all configs.
164
     */
165 2
    public function includeAll()
166
    {
167 2
        $still = true;
168 2
        while ($still) {
169 2
            $still = false;
170 2
            $include = $this->takeConfig()->rawItem('include');
171 2
            if ($include) {
172
                foreach ($include as $path) {
173
                    $still = $still || $this->takeConfig()->includeConfig($path);
174
                }
175
            }
176
        }
177 2
    }
178
179
    /**
180
     * Load project's config if configured.
181
     */
182 2
    public function loadConfig()
183
    {
184 2
        $path = $this->takeConfig()->rawItem('config');
185 2
        if ($path) {
186 2
            $this->module->loadExtraConfig($path);
187
        }
188 2
    }
189
190
    public function setRootDir($value)
191
    {
192
        $this->_rootDir = $value;
193
    }
194
195 2
    public function getRootDir()
196
    {
197 2
        if ($this->_rootDir === null) {
198 2
            $this->_rootDir = $this->findRootDir();
199
        }
200
201 2
        return $this->_rootDir;
202
    }
203
204
    /**
205
     * Chdirs to project's root by looking for config file in the current directory and up.
206
     * @throws InvalidParamException when failed to find
207
     * @return string path to the root directory of hidev project
208
     */
209 2
    protected function findRootDir()
210
    {
211 2
        $configDir = '.hidev';
212 2
        for ($i = 0; $i < 9; ++$i) {
213 2
            if (is_dir($configDir)) {
214 2
                return getcwd();
215
            }
216
            chdir('..');
217
        }
218
        throw new InvalidParamException("Not a hidev project (or any of the parent directories).\nUse `hidev init` to initialize hidev project.");
219
    }
220
221
    public function buildRootPath($subpath)
222
    {
223
        return $this->getRootDir() . DIRECTORY_SEPARATOR . $subpath;
224
    }
225
}
226