Completed
Push — master ( 0a1951...1a638f )
by Paweł
22:32 queued 13:24
created

src/Sylius/Behat/Context/Cli/InstallerContext.php (2 issues)

Labels
Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Sylius\Behat\Context\Cli;
13
14
use Behat\Behat\Context\Context;
15
use Sylius\Bundle\CoreBundle\Command\InstallSampleDataCommand;
16
use Sylius\Bundle\CoreBundle\Command\SetupCommand;
17
use Symfony\Bundle\FrameworkBundle\Console\Application;
18
use Symfony\Component\Console\Helper\QuestionHelper;
19
use Symfony\Component\Console\Tester\CommandTester;
20
use Symfony\Component\HttpKernel\KernelInterface;
21
use Webmozart\Assert\Assert;
22
23
/**
24
 * @author Magdalena Banasiak <[email protected]>
25
 */
26
final class InstallerContext implements Context
27
{
28
    /**
29
     * @var KernelInterface
30
     */
31
    private $kernel;
32
33
    /**
34
     * @var Application
35
     */
36
    private $application;
37
38
    /**
39
     * @var CommandTester
40
     */
41
    private $tester;
42
43
    /**
44
     * @var QuestionHelper
45
     */
46
    private $questionHelper;
47
48
    /**
49
     * @var SetupCommand
50
     */
51
    private $command;
52
53
    /**
54
     * @var array
55
     */
56
    private $inputChoices = [
57
        'currency' => 'USD',
58
        'e-mail' => '[email protected]',
59
        'password' => 'pswd',
60
        'confirmation' => 'pswd',
61
    ];
62
63
    /**
64
     * @param KernelInterface $kernel
65
     */
66
    public function __construct(KernelInterface $kernel)
67
    {
68
        $this->kernel = $kernel;
69
    }
70
71
    /**
72
     * @When I run Sylius CLI installer
73
     */
74
    public function iRunSyliusCommandLineInstaller()
75
    {
76
        $this->application = new Application($this->kernel);
77
        $this->application->add(new SetupCommand());
78
79
        $this->command = $this->application->find('sylius:install:setup');
80
        $this->tester = new CommandTester($this->command);
81
82
        $this->iExecuteCommandWithInputChoices('sylius:install:setup');
83
    }
84
85
    /**
86
     * @Given I run Sylius Install Load Sample Data command
87
     */
88
    public function iRunSyliusInstallSampleDataCommand()
89
    {
90
        $this->application = new Application($this->kernel);
91
        $this->application->add(new InstallSampleDataCommand());
92
        $this->command = $this->application->find('sylius:install:sample-data');
93
        $this->tester = new CommandTester($this->command);
94
    }
95
96
    /**
97
     * @Given I confirm loading sample data
98
     */
99
    public function iConfirmLoadingData()
100
    {
101
        $this->iExecuteCommandAndConfirm('sylius:install:sample-data');
102
    }
103
104
    /**
105
     * @Then the command should finish successfully
106
     */
107
    public function commandSuccess()
108
    {
109
        Assert::same($this->tester->getStatusCode(), 0);
110
    }
111
112
    /**
113
     * @Then I should see output :text
114
     */
115
    public function iShouldSeeOutput($text)
116
    {
117
        Assert::contains($this->tester->getDisplay(), $text);
118
    }
119
120
    /**
121
     * @Given I do not provide an email
122
     */
123
    public function iDoNotProvideEmail()
124
    {
125
        $this->inputChoices['e-mail'] = '';
126
    }
127
128
    /**
129
     * @Given I do not provide a correct email
130
     */
131
    public function iDoNotProvideCorrectEmail()
132
    {
133
        $this->inputChoices['e-mail'] = 'janusz';
134
    }
135
136
    /**
137
     * @Given I provide full administrator data
138
     */
139
    public function iProvideFullAdministratorData()
140
    {
141
        $this->inputChoices['e-mail'] = '[email protected]';
142
        $this->inputChoices['password'] = 'pswd1$';
143
        $this->inputChoices['confirmation'] = $this->inputChoices['password'];
144
    }
145
146
    /**
147
     * @param string $input
148
     *
149
     * @return resource
150
     */
151
    protected function getInputStream($input)
152
    {
153
        $stream = fopen('php://memory', 'r+', false);
154
        fwrite($stream, $input);
155
        rewind($stream);
156
157
        return $stream;
158
    }
159
160
    /**
161
     * @param string $name
162
     */
163
    private function iExecuteCommandWithInputChoices($name)
164
    {
165
        $this->questionHelper = $this->command->getHelper('question');
166
        $inputString = implode(PHP_EOL, $this->inputChoices);
167
        $this->questionHelper->setInputStream($this->getInputStream($inputString.PHP_EOL));
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Helper\HelperInterface as the method setInputStream() does only exist in the following implementations of said interface: Symfony\Component\Console\Helper\QuestionHelper, Symfony\Component\Consol...r\SymfonyQuestionHelper.

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...
168
169
        try {
170
            $this->tester->execute(['command' => $name]);
171
        } catch (\Exception $e) {
172
        }
173
    }
174
175
    /**
176
     * @param string $name
177
     */
178
    private function iExecuteCommandAndConfirm($name)
179
    {
180
        $this->questionHelper = $this->command->getHelper('question');
181
        $inputString = 'y'.PHP_EOL;
182
        $this->questionHelper->setInputStream($this->getInputStream($inputString));
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Symfony\Component\Console\Helper\HelperInterface as the method setInputStream() does only exist in the following implementations of said interface: Symfony\Component\Console\Helper\QuestionHelper, Symfony\Component\Consol...r\SymfonyQuestionHelper.

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...
183
184
        try {
185
            $this->tester->execute(['command' => $name]);
186
        } catch (\Exception $e) {
187
        }
188
    }
189
}
190