InitProcessor::initBundleDirectoryStructure()   C
last analyzed

Complexity

Conditions 8
Paths 20

Size

Total Lines 75
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 75
rs 6.2413
cc 8
eloc 46
nc 20
nop 2

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SilverStripe\BehatExtension\Console\Processor;
4
5
use Symfony\Component\DependencyInjection\ContainerInterface;
6
use Symfony\Component\Console\Command\Command;
7
use Symfony\Component\Console\Input\InputArgument;
8
use Symfony\Component\Console\Input\InputInterface;
9
use Symfony\Component\Console\Output\OutputInterface;
10
use Symfony\Component\Console\Input\InputOption;
11
12
use Behat\Behat\Console\Processor\InitProcessor as BaseProcessor;
13
14
/**
15
 * Initializes a project for Behat usage, creating context files.
16
 */
17
class InitProcessor extends BaseProcessor
18
{
19
    private $container;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
20
21
    /**
22
     * @param ContainerInterface $container Container instance
23
     */
24
    public function __construct(ContainerInterface $container)
25
    {
26
        $this->container = $container;
27
    }
28
29
    /**
30
     * @param Command $command
31
     */
32
    public function configure(Command $command)
33
    {
34
        parent::configure($command);
35
        
36
        $command->addOption(
37
            '--namespace',
38
            null,
39
            InputOption::VALUE_OPTIONAL,
40
            "Optional namespace for FeatureContext, defaults to <foldername>\\Test\\Behaviour.\n"
41
        );
42
    }
43
44
    public function process(InputInterface $input, OutputInterface $output)
45
    {
46
        // throw exception if no features argument provided
47
        if (!$input->getArgument('features') && $input->getOption('init')) {
48
            throw new \InvalidArgumentException('Provide features argument in order to init suite.');
49
        }
50
51
        // initialize bundle structure and exit
52
        if ($input->getOption('init')) {
53
            $this->initBundleDirectoryStructure($input, $output);
54
55
            exit(0);
56
        }
57
    }
58
59
    /**
60
     * Inits bundle directory structure
61
     *
62
     * @param InputInterface  $input
63
     * @param OutputInterface $output
64
     */
65
    protected function initBundleDirectoryStructure(InputInterface $input, OutputInterface $output)
66
    {
67
        // Bootstrap SS so we can use module listing
68
        $frameworkPath = $this->container->getParameter('behat.silverstripe_extension.framework_path');
69
        $_GET['flush'] = 1;
70
        require_once $frameworkPath . '/core/Core.php';
71
        unset($_GET['flush']);
72
73
        $featuresPath = $input->getArgument('features');
74
        if (!$featuresPath) {
75
            throw new \InvalidArgumentException('Please specify a module name (e.g. "@mymodule")');
76
        }
77
78
        // Can't use 'behat.paths.base' since that's locked at this point to base folder (not module)
79
        $pathSuffix   = $this->container->getParameter('behat.silverstripe_extension.context.path_suffix');
80
        $currentModuleName = null;
0 ignored issues
show
Unused Code introduced by
$currentModuleName is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
81
        $modules = \SS_ClassLoader::instance()->getManifest()->getModules();
82
        $currentModuleName = $this->container->getParameter('behat.silverstripe_extension.module');
83
84
        // get module from short notation if path starts from @
85
        if (preg_match('/^\@([^\/\\\\]+)(.*)$/', $featuresPath, $matches)) {
86
            $currentModuleName = $matches[1];
87
            // TODO Replace with proper module loader once AJShort's changes are merged into core
88
            if (!array_key_exists($currentModuleName, $modules)) {
89
                throw new \InvalidArgumentException(sprintf('Module "%s" not found', $currentModuleName));
90
            }
91
            $currentModulePath = $modules[$currentModuleName];
92
        }
93
94
        if (!$currentModuleName) {
95
            throw new \InvalidArgumentException('Can not find module to initialize suite.');
96
        }
97
98
        // TODO Retrieve from module definition once that's implemented
99
        if ($input->getOption('namespace')) {
100
            $namespace = $input->getOption('namespace');
101
        } else {
102
            $namespace = ucfirst($currentModuleName);
103
        }
104
        $namespace .= '\\' . $this->container->getParameter('behat.silverstripe_extension.context.namespace_suffix');
105
106
        $featuresPath = rtrim($currentModulePath.DIRECTORY_SEPARATOR.$pathSuffix, DIRECTORY_SEPARATOR);
0 ignored issues
show
Bug introduced by
The variable $currentModulePath does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
107
        $basePath     = $this->container->getParameter('behat.paths.base').DIRECTORY_SEPARATOR;
108
        $bootstrapPath = $featuresPath.DIRECTORY_SEPARATOR.'bootstrap';
109
        $contextPath  = $bootstrapPath.DIRECTORY_SEPARATOR.'Context';
110
111
        if (!is_dir($featuresPath)) {
112
            mkdir($featuresPath, 0777, true);
113
            mkdir($bootstrapPath, 0777, true);
114
            // touch($bootstrapPath.DIRECTORY_SEPARATOR.'_manifest_exclude');
115
            $output->writeln(
116
                '<info>+d</info> ' .
117
                str_replace($basePath, '', realpath($featuresPath)) .
118
                ' <comment>- place your *.feature files here</comment>'
119
            );
120
        }
121
122
        if (!is_dir($contextPath)) {
123
            mkdir($contextPath, 0777, true);
124
125
            $className = $this->container->getParameter('behat.context.class');
126
            file_put_contents(
127
                $contextPath . DIRECTORY_SEPARATOR . $className . '.php',
128
                strtr($this->getFeatureContextSkelet(), array(
129
                    '%NAMESPACE%' => $namespace
130
                ))
131
            );
132
133
            $output->writeln(
134
                '<info>+f</info> ' .
135
                str_replace($basePath, '', realpath($contextPath)) . DIRECTORY_SEPARATOR .
136
                'FeatureContext.php <comment>- place your feature related code here</comment>'
137
            );
138
        }
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144
    protected function getFeatureContextSkelet()
145
    {
146
        return <<<'PHP'
147
<?php
148
149
namespace %NAMESPACE%;
150
151
use SilverStripe\BehatExtension\Context\SilverStripeContext,
152
    SilverStripe\BehatExtension\Context\BasicContext,
153
    SilverStripe\BehatExtension\Context\LoginContext,
154
    SilverStripe\BehatExtension\Context\FixtureContext,
155
    SilverStripe\Framework\Test\Behaviour\CmsFormsContext,
156
    SilverStripe\Framework\Test\Behaviour\CmsUiContext,
157
    SilverStripe\Cms\Test\Behaviour;
158
159
/**
160
 * Features context
161
 *
162
 * Context automatically loaded by Behat.
163
 * Uses subcontexts to extend functionality.
164
 */
165
class FeatureContext extends SilverStripeContext {
166
    
167
    /**
168
     * @var FixtureFactory
169
     */
170
    protected $fixtureFactory;
171
172
    /**
173
     * Initializes context.
174
     * Every scenario gets it's own context object.
175
     *
176
     * @param array $parameters context parameters (set them up through behat.yml)
177
     */
178
    public function __construct(array $parameters) {
179
        parent::__construct($parameters);
180
181
        $this->useContext('BasicContext', new BasicContext($parameters));
182
        $this->useContext('LoginContext', new LoginContext($parameters));
183
        $this->useContext('CmsFormsContext', new CmsFormsContext($parameters));
184
        $this->useContext('CmsUiContext', new CmsUiContext($parameters));
185
186
        $fixtureContext = new FixtureContext($parameters);
187
        $fixtureContext->setFixtureFactory($this->getFixtureFactory());
188
        $this->useContext('FixtureContext', $fixtureContext);
189
190
        // Use blueprints to set user name from identifier
191
        $factory = $fixtureContext->getFixtureFactory();
192
        $blueprint = \Injector::inst()->create('FixtureBlueprint', 'Member');
193
        $blueprint->addCallback('beforeCreate', function($identifier, &$data, &$fixtures) {
194
            if(!isset($data['FirstName'])) $data['FirstName'] = $identifier;
195
        });
196
        $factory->define('Member', $blueprint);
197
198
        // Auto-publish pages
199
        if (class_exists('SiteTree')) {
200
            foreach(\ClassInfo::subclassesFor('SiteTree') as $id => $class) {
201
                $blueprint = \Injector::inst()->create('FixtureBlueprint', $class);
202
                $blueprint->addCallback('afterCreate', function($obj, $identifier, &$data, &$fixtures) {
203
                    $obj->publish('Stage', 'Live');
204
                });
205
                $factory->define($class, $blueprint);
206
            }
207
        }
208
    }
209
210
    public function setMinkParameters(array $parameters) {
211
        parent::setMinkParameters($parameters);
212
        
213
        if(isset($parameters['files_path'])) {
214
            $this->getSubcontext('FixtureContext')->setFilesPath($parameters['files_path']);    
215
        }
216
    }
217
218
    /**
219
     * @return FixtureFactory
220
     */
221
    public function getFixtureFactory() {
222
        if(!$this->fixtureFactory) {
223
            $this->fixtureFactory = \Injector::inst()->create('BehatFixtureFactory');
224
        }
225
226
        return $this->fixtureFactory;
227
    }
228
229
    public function setFixtureFactory(FixtureFactory $factory) {
230
        $this->fixtureFactory = $factory;
231
    }
232
233
    //
234
    // Place your definition and hook methods here:
235
    //
236
    //    /**
237
    //     * @Given /^I have done something with "([^"]*)"$/
238
    //     */
239
    //    public function iHaveDoneSomethingWith($argument) {
240
    //        $container = $this->kernel->getContainer();
241
    //        $container->get('some_service')->doSomethingWith($argument);
242
    //    }
243
    //
244
}
245
246
PHP;
247
    }
248
}
249