Completed
Push — master ( d3eeb5...4b4eb0 )
by Nils
01:58
created

LeankoalaReporter::send()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 11
rs 9.4285
cc 3
eloc 7
nc 3
nop 8

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
namespace whm\Smoke\Extensions\SmokeReporter\Reporter;
4
5
use Koalamon\Client\Reporter\Event;
6
use Koalamon\Client\Reporter\Event\Attribute;
7
use Koalamon\Client\Reporter\Event\Processor\MongoDBProcessor;
8
use Koalamon\Client\Reporter\Reporter as KoalaReporter;
9
use Symfony\Component\Console\Output\OutputInterface;
10
use whm\Smoke\Config\Configuration;
11
use whm\Smoke\Extensions\Leankoala\LeankoalaExtension;
12
use whm\Smoke\Extensions\SmokeResponseRetriever\Retriever\Retriever;
13
use whm\Smoke\Rules\CheckResult;
14
use whm\Smoke\Scanner\Result;
15
16
/**
17
 * Class XUnitReporter.
18
 */
19
class LeankoalaReporter implements Reporter
20
{
21
    /**
22
     * @var Result[]
23
     */
24
    private $results = [];
25
26
    /**
27
     * @var Configuration
28
     */
29
    private $config;
30
    private $system;
31
    private $collect;
32
    private $identifier;
33
    private $systemUseRetriever;
34
    private $tool = 'smoke';
35
    private $groupBy;
36
    private $server;
37
    private $addComingFrom;
38
39
    /**
40
     * @var KoalaReporter
41
     */
42
    private $reporter;
43
44
    /**
45
     * @var Retriever
46
     */
47
    private $retriever;
48
49
    private $output;
50
51
    /**
52
     * @var LeankoalaExtension
53
     */
54
    private $leankoalaExtension;
55
56
    const STATUS_SUCCESS = 'success';
57
    const STATUS_FAILURE = 'failure';
58
59
    public function init($apiKey, Configuration $_configuration, OutputInterface $_output, $server = 'https://webhook.koalamon.com', $system = '', $identifier = '', $tool = '', $collect = true, $systemUseRetriever = false, $groupBy = false, $addComingFrom = true, $useMongo = true)
60
    {
61
        $httpClient = new \GuzzleHttp\Client();
62
63
        $this->reporter = new KoalaReporter('', $apiKey, $httpClient, $server);
64
65
        if ($useMongo) {
66
            $this->reporter->setEventProcessor(MongoDBProcessor::createByEnvironmentVars('leankoala'));
67
        }
68
69
        $this->config = $_configuration;
70
        $this->systemUseRetriever = $systemUseRetriever;
71
72
        $this->system = $system;
73
        $this->collect = $collect;
74
        $this->identifier = $identifier;
75
        $this->groupBy = $groupBy;
76
77
        $this->addComingFrom = $addComingFrom;
78
79
        if ($tool) {
80
            $this->tool = $tool;
81
        }
82
83
        $this->leankoalaExtension = $_configuration->getExtension('Leankoala');
84
85
        $this->server = $server;
86
        $this->output = $_output;
87
    }
88
89
    public function setResponseRetriever(Retriever $retriever)
90
    {
91
        $this->retriever = $retriever;
92
    }
93
94
    public function processResults($results)
95
    {
96
        $this->results[] = $results;
97
    }
98
99
    public function finish()
100
    {
101
        if ($this->collect) {
102
            $this->sendCollectedResults();
103
        } else {
104
            $this->sendSingleResults();
105
        }
106
    }
107
108
    private function getComponent($ruleName)
109
    {
110
        $ruleArray = explode('_', $ruleName);
111
        $component = array_pop($ruleArray);
112
113
        return $component;
114
    }
115
116
    private function sendCollectedResults()
117
    {
118
        $checks = [];
119
120
        foreach ($this->results as $results) {
121
            foreach ($results as $result) {
0 ignored issues
show
Bug introduced by
The expression $results of type object<whm\Smoke\Scanner\Result> is not traversable.
Loading history...
122
                /* @var CheckResult $result */
123
                $tool = 'Smoke' . $result->getRuleName();
124
                $checks[$tool][] = $result;
125
            }
126
        }
127
128
        foreach ($checks as $toolName => $results) {
129
            $attributes = array();
130
131
            if (count($results) === 0) {
132
                continue;
133
            }
134
135
            $message = 'The smoke test for #system_name# failed (Rule: ' . $toolName . ').<ul>';
136
            $status = Event::STATUS_SUCCESS;
137
            $failureCount = 0;
138
            $identifier = $toolName . '_' . $this->system;
139
140
            foreach ($results as $result) {
141
                /** @var CheckResult $result */
142
                if ($result->getStatus() === CheckResult::STATUS_FAILURE) {
143
                    $comingFrom = '';
144
                    if ($this->addComingFrom && $this->retriever->getComingFrom($result->getResponse()->getUri())) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method getUri() does only exist in the following implementations of said interface: phm\HttpWebdriverClient\...t\Chrome\ChromeResponse, phm\HttpWebdriverClient\...t\Guzzle\GuzzleResponse, phm\HttpWebdriverClient\...\Client\Guzzle\Response.

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...
145
                        $comingFrom = ', coming from: ' . $this->retriever->getComingFrom($result->getResponse()->getUri());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method getUri() does only exist in the following implementations of said interface: phm\HttpWebdriverClient\...t\Chrome\ChromeResponse, phm\HttpWebdriverClient\...t\Guzzle\GuzzleResponse, phm\HttpWebdriverClient\...\Client\Guzzle\Response.

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...
146
                    }
147
                    $message .= '<li>' . $result->getMessage() . ' (url: ' . (string)$result->getResponse()->getUri() . $comingFrom . ')</li>';
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method getUri() does only exist in the following implementations of said interface: phm\HttpWebdriverClient\...t\Chrome\ChromeResponse, phm\HttpWebdriverClient\...t\Guzzle\GuzzleResponse, phm\HttpWebdriverClient\...\Client\Guzzle\Response.

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...
148
                    ++$failureCount;
149
                }
150
            }
151
            if ($failureCount > 0) {
152
                $status = Event::STATUS_FAILURE;
153
                $message .= '</ul>';
154
                $firstResult = array_pop($results);
155
                $attributes[] = new Attribute('html-content', (string)$firstResult->getResponse()->getBody(), true);
156
            } else {
157
                $message = 'All checks for system "#system_name#" succeeded [SmokeBasic:' . $toolName . '].';
158
            }
159
160
            $this->send($identifier, $this->system, $message, $status, $failureCount, $this->tool, $this->system, $attributes);
161
        }
162
    }
163
164
    private function sendSingleResults()
165
    {
166
        foreach ($this->results as $results) {
167
            foreach ($results as $result) {
0 ignored issues
show
Bug introduced by
The expression $results of type object<whm\Smoke\Scanner\Result> is not traversable.
Loading history...
168
                /* @var CheckResult $result */
169
170
                $identifier = '_' . $this->getIdentifier($result);
171
                $tool = $this->getPrefix($result->getRuleName());
172
173
                $component = $this->getComponent($result->getRuleName());
174
                $system = $this->leankoalaExtension->getSystem($component);
175
176
                $attributes = array();
177
                if ($result->getStatus() == CheckResult::STATUS_FAILURE) {
178
                    $body = (string)$result->getResponse()->getBody();
179
                    if ($body == "") {
180
                        $attributes[] = new Attribute('html content', '<empty>');
181
                    } else {
182
                        $attributes[] = new Attribute('html content', $body, true);
183
                    }
184
                    $attributes[] = new Attribute('http header', json_encode($result->getResponse()->getHeaders()), true);
185
                    $attributes[] = new Attribute('http status code', $result->getResponse()->getStatusCode());
186
                }
187
188
                $checkResultAttributes = $result->getAttributes();
189
                foreach ($checkResultAttributes as $checkResultAttribute) {
190
                    $attributes[] = new Attribute($checkResultAttribute->getKey(), $checkResultAttribute->getValue(), $checkResultAttribute->isIsStorable());
191
                }
192
193
                if ($this->system) {
194
                    $currentSystem = $this->system;
195
                } else {
196
                    $currentSystem = $system;
197
                }
198
199
                $this->send(
200
                    $identifier,
201
                    $currentSystem,
202
                    $result->getMessage() . ' (url: ' . (string)$result->getResponse()->getUri() . ')',
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Psr\Http\Message\ResponseInterface as the method getUri() does only exist in the following implementations of said interface: phm\HttpWebdriverClient\...t\Chrome\ChromeResponse, phm\HttpWebdriverClient\...t\Guzzle\GuzzleResponse, phm\HttpWebdriverClient\...\Client\Guzzle\Response.

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...
203
                    $result->getStatus(),
204
                    $result->getValue(),
205
                    $tool,
206
                    $component,
207
                    $attributes
208
                );
209
            }
210
        }
211
    }
212
213
    private function getIdentifier(CheckResult $result)
214
    {
215
        return $this->tool . '_' . $result->getRuleName();
216
    }
217
218
    private function getPrefix($string)
219
    {
220
        return substr($string, 0, strpos($string, '_'));
221
    }
222
223
    /**
224
     * @param $identifier
225
     * @param $system
226
     * @param $message
227
     * @param $status
228
     * @param $value
229
     * @param $tool
230
     * @param $component
231
     * @param Attribute[] $attributes
232
     */
233
    private function send($identifier, $system, $message, $status, $value, $tool, $component, $attributes = [])
234
    {
235
        if ($status !== CheckResult::STATUS_NONE) {
236
            $event = new Event($identifier, $system, $status, $tool, $message, $value, '', $component);
237
            $event->addAttribute(new Attribute('_config', json_encode($this->config->getConfigArray()), true));
238
            foreach ($attributes as $attribute) {
239
                $event->addAttribute($attribute);
240
            }
241
            $this->reporter->sendEvent($event);
242
        }
243
    }
244
}
245