Completed
Push — master ( d964e4...900267 )
by Jeroen
23:03 queued 15:42
created

VersionChecker   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 215
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Test Coverage

Coverage 84.93%

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 6
dl 0
loc 215
ccs 62
cts 73
cp 0.8493
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 10 1
A isEnabled() 0 4 1
A periodicallyCheck() 0 11 3
A check() 0 38 4
A getClient() 0 8 2
A setClient() 0 4 1
A getLockPath() 0 7 1
A getPackages() 0 24 5
A parseComposer() 0 15 3
1
<?php
2
3
namespace Kunstmaan\AdminBundle\Helper\VersionCheck;
4
5
use Doctrine\Common\Cache\Cache;
6
use Exception;
7
use GuzzleHttp\Client;
8
use Kunstmaan\AdminBundle\Helper\VersionCheck\Exception\ParseException;
9
use Symfony\Component\DependencyInjection\ContainerInterface;
10
use Symfony\Contracts\Translation\TranslatorInterface;
11
12
/**
13
 * Version checker
14
 */
15
class VersionChecker
16
{
17
    /**
18
     * @var ContainerInterface
19
     */
20
    private $container;
21
22
    /**
23
     * @var Cache
24
     */
25
    private $cache;
26
27
    /**
28
     * @var string
29
     */
30
    private $webserviceUrl;
31
32
    /**
33
     * @var int
34
     */
35
    private $cacheTimeframe;
36
37
    /**
38
     * @var bool
39
     */
40
    private $enabled;
41
42
    /**
43
     * @var Client
44
     */
45
    private $client;
46
47
    /**
48
     * @var TranslatorInterface
49
     */
50
    private $translator;
51
52
    /**
53
     * Constructor
54
     *
55
     * @param ContainerInterface $container
56
     * @param Cache              $cache
57
     */
58 7
    public function __construct(ContainerInterface $container, Cache $cache, TranslatorInterface $translator)
59
    {
60 7
        $this->container = $container;
61 7
        $this->cache = $cache;
62 7
        $this->translator = $translator;
63
64 7
        $this->webserviceUrl = $this->container->getParameter('version_checker.url');
65 7
        $this->cacheTimeframe = $this->container->getParameter('version_checker.timeframe');
66 7
        $this->enabled = $this->container->getParameter('version_checker.enabled');
67 7
    }
68
69
    /**
70
     * Check that the version check is enabled.
71
     *
72
     * @return bool
73
     */
74 7
    public function isEnabled()
75
    {
76 7
        return $this->enabled;
77
    }
78
79
    /**
80
     * Check if we recently did a version check, if not do one now.
81
     *
82
     * @throws ParseException
83
     */
84 1
    public function periodicallyCheck()
85
    {
86 1
        if (!$this->isEnabled()) {
87
            return;
88
        }
89
90 1
        $data = $this->cache->fetch('version_check');
91 1
        if (!\is_array($data)) {
92
            $this->check();
93
        }
94 1
    }
95
96
    /**
97
     * Get the version details via webservice.
98
     *
99
     * @return mixed a list of bundles if available
100
     *
101
     * @throws ParseException
102
     */
103 5
    public function check()
104
    {
105 5
        if (!$this->isEnabled()) {
106
            return;
107
        }
108
109 5
        $host = $this->container->get('request_stack')->getCurrentRequest()->getHttpHost();
110 5
        $console = realpath($this->container->get('kernel')->getProjectDir().'/bin/console');
111 5
        $installed = filectime($console);
112 5
        $bundles = $this->parseComposer();
113 2
        $title = $this->container->getParameter('kunstmaan_admin.website_title');
114
115 2
        $jsonData = json_encode(array(
116 2
            'host' => $host,
117 2
            'installed' => $installed,
118 2
            'bundles' => $bundles,
119 2
            'project' => $this->translator->trans($title),
120
        ));
121
122
        try {
123 2
            $client = $this->getClient();
124 2
            $response = $client->post($this->webserviceUrl, ['body' => $jsonData]);
125 1
            $contents = $response->getBody()->getContents();
126 1
            $data = json_decode($contents);
127
128 1
            if (null === $data) {
129
                return false;
130
            }
131
132
            // Save the result in the cache to make sure we don't do the check too often
133 1
            $this->cache->save('version_check', $data, $this->cacheTimeframe);
134
135 1
            return $data;
136 1
        } catch (Exception $e) {
137
            // We did not receive valid json
138 1
            return false;
139
        }
140
    }
141
142
    /**
143
     * @return Client
144
     */
145 1
    public function getClient()
146
    {
147 1
        if (!$this->client) {
148 1
            $this->client = new Client(array('connect_timeout' => 3, 'timeout' => 1));
149
        }
150
151 1
        return $this->client;
152
    }
153
154
    /**
155
     * @param Client $client
156
     */
157
    public function setClient($client)
158
    {
159
        $this->client = $client;
160
    }
161
162
    /**
163
     * Returns the absolute path to the composer.lock file.
164
     *
165
     * @return string
166
     */
167
    protected function getLockPath()
168
    {
169
        $kernel = $this->container->get('kernel');
170
        $rootPath = $kernel->getProjectDir();
171
172
        return $rootPath.'/composer.lock';
173
    }
174
175
    /**
176
     * Returns a list of composer packages.
177
     *
178
     * @return array
179
     *
180
     * @throws ParseException
181
     */
182 4
    protected function getPackages()
183
    {
184 4
        $translator = $this->container->get('translator');
185 4
        $errorMessage = $translator->trans('settings.version.error_parsing_composer');
186
187 4
        $composerPath = $this->getLockPath();
188 4
        if (!file_exists($composerPath)) {
189 1
            throw new ParseException($translator->trans('settings.version.composer_lock_not_found'));
190
        }
191
192 3
        $json = file_get_contents($composerPath);
193 3
        $result = json_decode($json, true);
194
195 3
        if (json_last_error() !== JSON_ERROR_NONE) {
196 1
            throw new ParseException($errorMessage.' (#'.json_last_error().')');
197
        }
198
199 2
        if (\array_key_exists('packages', $result) && \is_array($result['packages'])) {
200 1
            return $result['packages'];
201
        }
202
203
        // No package list in JSON structure
204 1
        throw new ParseException($errorMessage);
205
    }
206
207
    /**
208
     * Parse the composer.lock file to get the currently used versions of the kunstmaan bundles.
209
     *
210
     * @return array
211
     *
212
     * @throws ParseException
213
     */
214 4
    protected function parseComposer()
215
    {
216 4
        $bundles = array();
217 4
        foreach ($this->getPackages() as $package) {
218 1
            if (!strncmp($package['name'], 'kunstmaan/', \strlen('kunstmaan/'))) {
219 1
                $bundles[] = array(
220 1
                    'name' => $package['name'],
221 1
                    'version' => $package['version'],
222 1
                    'reference' => $package['source']['reference'],
223
                );
224
            }
225
        }
226
227 1
        return $bundles;
228
    }
229
}
230