Completed
Push — master ( 33a55e...ca53a0 )
by Nils
07:47
created

Configuration::getClient()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 23
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 23
rs 8.5906
cc 5
eloc 15
nc 5
nop 0
1
<?php
2
3
namespace whm\Smoke\Config;
4
5
use Cache\Adapter\Filesystem\FilesystemCachePool;
6
use League\Flysystem\Adapter\Local;
7
use League\Flysystem\Filesystem;
8
use phm\HttpWebdriverClient\Http\Client\Decorator\CacheDecorator;
9
use phm\HttpWebdriverClient\Http\Client\Guzzle\GuzzleClient;
10
use phm\HttpWebdriverClient\Http\Client\HttpClient;
11
use phmLabs\Components\Annovent\Dispatcher;
12
use PhmLabs\Components\Init\Init;
13
use Symfony\Component\Yaml\Yaml;
14
use whm\Html\Uri;
15
use whm\Smoke\Http\Session;
16
use whm\Smoke\Rules\Rule;
17
use whm\Smoke\Scanner\SessionContainer;
18
19
class Configuration
20
{
21
    const DEFAULT_SETTINGS = 'analyze.yml';
22
23
    private $startUri;
24
25
    private $rules = [];
26
27
    private $configArray;
28
29
    private $eventDispatcher;
30
31
    private $extensions = array();
32
33
    private $runLevels = array();
34
35
    /**
36
     * @var SessionContainer
37
     */
38
    private $sessionContainer;
39
40
    public function __construct(Uri $uri, Dispatcher $eventDispatcher, array $configArray, array $defaultSettings = null)
41
    {
42
        $this->eventDispatcher = $eventDispatcher;
43
        Init::registerGlobalParameter('_configuration', $this);
44
45
        $this->initConfigArray($configArray, $defaultSettings);
46
47
        if (array_key_exists('sessions', $this->configArray)) {
48
            $this->initSessionContainer($this->configArray['sessions']);
49
        } else {
50
            $this->sessionContainer = new SessionContainer();
51
        }
52
53
        if (array_key_exists('extensions', $this->configArray)) {
54
            $this->addListener($this->configArray['extensions']);
55
        }
56
57
        if (!array_key_exists('rules', $this->configArray)) {
58
            $this->configArray['rules'] = [];
59
        }
60
61
        $this->startUri = $uri;
62
        $this->initRules($this->configArray['rules']);
63
    }
64
65
    private function initConfigArray(array $configArray, array $defaultSettings = null)
66
    {
67
        if ($defaultSettings === null) {
68
            $defaultSettings = Yaml::parse(file_get_contents(__DIR__ . '/../settings/' . self::DEFAULT_SETTINGS));
69
        }
70
71
        if (count($configArray) === 0) {
72
            $configArray = $defaultSettings;
73
        }
74
75
        if (array_key_exists('options', $configArray)) {
76
            if (array_key_exists('extendDefault', $configArray['options'])) {
77
                if ($configArray['options']['extendDefault'] === true) {
78
                    $configArray = array_replace_recursive($defaultSettings, $configArray);
79
                }
80
            }
81
        }
82
83
        $this->configArray = $configArray;
84
    }
85
86
    private function initSessionContainer(array $sessionsArray)
87
    {
88
        $this->sessionContainer = new SessionContainer();
89
90
        foreach ($sessionsArray as $sessionName => $sessionsElement) {
91
            $session = new Session();
92
93
            if (array_key_exists('cookies', $sessionsElement)) {
94
                foreach ($sessionsElement['cookies'] as $key => $value) {
95
                    $session->addCookie($key, $value);
96
                }
97
            }
98
99
            $this->sessionContainer->addSession($sessionName, $session);
100
        }
101
    }
102
103
    private function addListener(array $listenerArray)
104
    {
105
        foreach ($listenerArray as $key => $listenerConfig) {
106
            $extension = Init::initialize($listenerConfig);
107
            $this->extensions[$key] = $extension;
108
            $this->eventDispatcher->connectListener($extension);
109
        }
110
    }
111
112
    /**
113
     * @return Uri
114
     */
115
    public function getStartUri()
116
    {
117
        return $this->startUri;
118
    }
119
120
    /**
121
     * This function initializes all the rules and sets the log level.
122
     *
123
     * @param array $rulesArray
124
     */
125
    private function initRules(array $rulesArray)
126
    {
127
        $this->rules = Init::initializeAll($rulesArray);
128
    }
129
130
    /**
131
     * Returns the log level of a given rule.
132
     *
133
     * @param string $key
134
     *
135
     * @return int
136
     */
137
    public function getRuleRunLevel($key)
138
    {
139
        return $this->runLevels[$key];
140
    }
141
142
    /**
143
     * @return Rule[]
144
     */
145
    public function getRules()
146
    {
147
        return $this->rules;
148
    }
149
150
    public function getSessionContainer()
151
    {
152
        return $this->sessionContainer;
153
    }
154
155
    public function hasSection($section)
156
    {
157
        return array_key_exists($section, $this->configArray);
158
    }
159
160
    /**
161
     * @param $section
162
     *
163
     * @return array
164
     */
165
    public function getSection($section)
166
    {
167
        if ($this->hasSection($section)) {
168
            return $this->configArray[$section];
169
        } else {
170
            throw new \RuntimeException('The section (' . $section . ') you are trying to access does not exist.');
171
        }
172
    }
173
174 View Code Duplication
    public function getExtension($name)
175
    {
176
        if (array_key_exists($name, $this->extensions)) {
177
            return $this->extensions[$name];
178
        } else {
179
            throw new \RuntimeException('The extension ("' . $name . '") you are trying to access does not exist. Registered extensions are: ' . implode(' ,', array_keys($this->extensions)) . '.');
180
        }
181
    }
182
183
    public function addExtension($name, $extension)
184
    {
185
        $this->extensions[$name] = $extension;
186
        $this->eventDispatcher->connectListener($extension);
187
    }
188
189
    public function getConfigArray()
190
    {
191
        return $this->configArray;
192
    }
193
194
    /**
195
     * @return HttpClient
196
     */
197
    public function getClient()
198
    {
199
        if (array_key_exists('client', $this->configArray)) {
200
201
            try {
202
                $client = Init::initialize($this->configArray['client']);
203
            } catch (\Exception $e) {
204
                throw new ConfigurationException('Error initializing client (' . $e->getMessage() . ')');
205
            }
206
207
            if (array_key_exists('cache', $this->configArray['client'])) {
208
                if ($this->configArray['client']['cache'] == true) {
209
                    $filesystemAdapter = new Local('/tmp/cached/');
210
                    $filesystem = new Filesystem($filesystemAdapter);
211
                    $cachePoolInterface = new FilesystemCachePool($filesystem);
212
                    return new CacheDecorator($client, $cachePoolInterface);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \phm\HttpWebd..., $cachePoolInterface); (phm\HttpWebdriverClient\...ecorator\CacheDecorator) is incompatible with the return type documented by whm\Smoke\Config\Configuration::getClient of type phm\HttpWebdriverClient\Http\Client\HttpClient.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
213
                }
214
            }
215
            return $client;
216
        } else {
217
            return new GuzzleClient();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \phm\HttpWebd...\Guzzle\GuzzleClient(); (phm\HttpWebdriverClient\...ent\Guzzle\GuzzleClient) is incompatible with the return type documented by whm\Smoke\Config\Configuration::getClient of type phm\HttpWebdriverClient\Http\Client\HttpClient.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
218
        }
219
    }
220
}
221