Completed
Push — master ( b9c485...94fed1 )
by Michał
13:51
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\InstallerBundle\Command\InstallSampleDataCommand;
16
use Sylius\Bundle\InstallerBundle\Command\SetupCommand;
17
use Symfony\Bundle\FrameworkBundle\Console\Application;
18
use Symfony\Component\Console\Helper\DialogHelper;
19
use Symfony\Component\Console\Tester\CommandTester;
20
use Symfony\Component\EventDispatcher\EventDispatcher;
21
use Symfony\Component\HttpKernel\KernelInterface;
22
use Webmozart\Assert\Assert;
23
24
/**
25
 * @author Magdalena Banasiak <[email protected]>
26
 */
27
final class InstallerContext implements Context
28
{
29
    /**
30
     * @var KernelInterface
31
     */
32
    private $kernel;
33
34
    /**
35
     * @var Application
36
     */
37
    private $application;
38
39
    /**
40
     * @var CommandTester
41
     */
42
    private $tester;
43
44
    /**
45
     * @var DialogHelper
46
     */
47
    private $dialog;
48
49
    /**
50
     * @var SetupCommand
51
     */
52
    private $command;
53
54
    /**
55
     * @var array
56
     */
57
    private $inputChoices = [
58
        'currency' => '',
59
        'name' => ' Name',
60
        'surname' => ' Surname',
61
        'e-mail' => ' [email protected]',
62
        'password' => ' pswd',
63
        'confirmation' => ' pswd',
64
    ];
65
66
    /**
67
     * @param KernelInterface $kernel
68
     */
69
    public function __construct(KernelInterface $kernel)
70
    {
71
        $this->kernel = $kernel;
72
    }
73
74
    /**
75
     * @When I run Sylius CLI installer
76
     */
77
    public function iRunSyliusCommandLineInstaller()
78
    {
79
        $this->application = new Application($this->kernel);
80
        $this->application->add(new SetupCommand());
81
82
        $this->command = $this->application->find('sylius:install:setup');
83
        $this->tester = new CommandTester($this->command);
84
85
        $this->iExecuteCommandWithInputChoices('sylius:install:setup');
86
    }
87
88
    /**
89
     * @Given I run Sylius Install Load Sample Data command
90
     */
91
    public function iRunSyliusInstallSampleDataCommand()
92
    {
93
        $this->application = new Application($this->kernel);
94
        $this->application->add(new InstallSampleDataCommand());
95
        $this->command = $this->application->find('sylius:install:sample-data');
96
        $this->tester = new CommandTester($this->command);
97
    }
98
99
    /**
100
     * @Given I confirm loading sample data
101
     */
102
    public function iConfirmLoadingData()
103
    {
104
        $this->iExecuteCommandAndConfirm('sylius:install:sample-data');
105
    }
106
107
    /**
108
     * @Then the command should finish successfully
109
     */
110
    public function commandSuccess()
111
    {
112
        Assert::same($this->tester->getStatusCode(), 0);
113
    }
114
115
    /**
116
     * @Then I should see output :text
117
     */
118
    public function iShouldSeeOutput($text)
119
    {
120
        Assert::contains($this->tester->getDisplay(), $text);
121
    }
122
123
    /**
124
     * @Given I do not provide a currency
125
     */
126
    public function iDoNotProvideCurrency()
127
    {
128
        $this->inputChoices['currency'] = '';
129
    }
130
131
    /**
132
     * @Given I do not provide a name
133
     */
134
    public function iDoNotProvideName()
135
    {
136
        array_splice($this->inputChoices, 1, 0, '');
137
    }
138
139
    /**
140
     * @Given I do not provide a surname
141
     */
142
    public function iDoNotProvideSurname()
143
    {
144
        array_splice($this->inputChoices, 2, 0, '');
145
    }
146
147
    /**
148
     * @Given I do not provide an email
149
     */
150
    public function iDoNotProvideEmail()
151
    {
152
        array_splice($this->inputChoices, 3, 0, '');
153
    }
154
155
    /**
156
     * @Given I do not provide a correct email
157
     */
158
    public function iDoNotProvideCorrectEmail()
159
    {
160
        array_splice($this->inputChoices, 3, 0, 'email');
161
    }
162
163
    /**
164
     * @Given I provide currency :code
165
     */
166
    public function iProvideCurrency($code)
167
    {
168
        $this->inputChoices['currency'] = $code;
169
    }
170
171
    /**
172
     * @Given I provide full administrator data
173
     */
174
    public function iProvideFullAdministratorData()
175
    {
176
        $this->inputChoices['name'] = 'AdminName';
177
        $this->inputChoices['surname'] = 'AdminSurname';
178
        $this->inputChoices['e-mail'] = '[email protected]';
179
        $this->inputChoices['password'] = 'pswd1$';
180
        $this->inputChoices['confirmation'] = $this->inputChoices['password'];
181
    }
182
183
    /**
184
     * @param string $input
185
     *
186
     * @return resource
187
     */
188
    protected function getInputStream($input)
189
    {
190
        $stream = fopen('php://memory', 'r+', false);
191
        fputs($stream, $input);
192
        rewind($stream);
193
194
        return $stream;
195
    }
196
197
    /**
198
     * @param string $name
199
     */
200
    private function iExecuteCommandWithInputChoices($name)
201
    {
202
        $this->dialog = $this->command->getHelper('dialog');
203
        $inputString = join(PHP_EOL, $this->inputChoices);
204
        $this->dialog->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\DialogHelper, 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...
205
206
        $this->tester->execute(['command' => $name]);
207
    }
208
209
    /**
210
     * @param string $name
211
     */
212
    private function iExecuteCommandAndConfirm($name)
213
    {
214
        $this->dialog = $this->command->getHelper('dialog');
215
        $inputString = 'y'.PHP_EOL;
216
        $this->dialog->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\DialogHelper, 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...
217
218
        $this->tester->execute(['command' => $name]);
219
    }
220
}
221