These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Kunstmaan\AdminBundle\Helper\VersionCheck; |
||
4 | |||
5 | use Doctrine\Common\Cache\Cache; |
||
6 | use Doctrine\Common\Cache\CacheProvider; |
||
7 | use Exception; |
||
8 | use GuzzleHttp\Client; |
||
9 | use Kunstmaan\AdminBundle\Helper\VersionCheck\Exception\ParseException; |
||
10 | use Symfony\Component\Cache\Adapter\AdapterInterface; |
||
11 | use Symfony\Component\Cache\Adapter\DoctrineAdapter; |
||
12 | use Symfony\Component\DependencyInjection\ContainerInterface; |
||
13 | use Symfony\Component\Translation\TranslatorInterface as LegacyTranslatorInterface; |
||
14 | use Symfony\Contracts\Translation\TranslatorInterface; |
||
15 | |||
16 | /** |
||
17 | * Version checker |
||
18 | */ |
||
19 | class VersionChecker |
||
20 | { |
||
21 | public const CACHE_KEY = 'version_check'; |
||
22 | |||
23 | /** |
||
24 | * @var ContainerInterface |
||
25 | */ |
||
26 | private $container; |
||
27 | |||
28 | /** |
||
29 | * @var AdapterInterface |
||
30 | */ |
||
31 | private $cache; |
||
32 | |||
33 | /** |
||
34 | * @var string |
||
35 | */ |
||
36 | private $webserviceUrl; |
||
37 | |||
38 | /** |
||
39 | * @var int |
||
40 | */ |
||
41 | private $cacheTimeframe; |
||
42 | |||
43 | /** |
||
44 | * @var bool |
||
45 | */ |
||
46 | private $enabled; |
||
47 | |||
48 | /** |
||
49 | * @var Client |
||
50 | */ |
||
51 | private $client; |
||
52 | |||
53 | /** |
||
54 | * @var TranslatorInterface|LegacyTranslatorInterface |
||
55 | */ |
||
56 | private $translator; |
||
57 | |||
58 | /** |
||
59 | * @param CacheProvider|AdapterInterface $cache |
||
60 | */ |
||
61 | 10 | public function __construct(ContainerInterface $container, /* AdapterInterface */$cache, $translator) |
|
62 | { |
||
63 | 10 | $this->container = $container; |
|
64 | |||
65 | 10 | if (!$cache instanceof CacheProvider && !$cache instanceof AdapterInterface) { |
|
66 | // NEXT_MAJOR Add AdapterInterface typehint for the $cache parameter |
||
67 | 1 | throw new \InvalidArgumentException(sprintf('The "$cache" parameter should extend from "%s" or implement "%s"', CacheProvider::class, AdapterInterface::class)); |
|
68 | } |
||
69 | |||
70 | 9 | $this->cache = $cache; |
|
71 | 9 | if ($cache instanceof CacheProvider) { |
|
72 | 2 | @trigger_error(sprintf('Passing an instance of "%s" as the second argument in "%s" is deprecated since KunstmaanAdminBundle 5.7 and an instance of "%s" will be required in KunstmaanAdminBundle 6.0.', CacheProvider::class, __METHOD__, AdapterInterface::class), E_USER_DEPRECATED); |
|
0 ignored issues
–
show
|
|||
73 | |||
74 | 2 | $this->cache = new DoctrineAdapter($cache); |
|
75 | } |
||
76 | |||
77 | // NEXT_MAJOR Add "Symfony\Contracts\Translation\TranslatorInterface" typehint when sf <4.4 support is removed. |
||
78 | 9 | if (!$translator instanceof TranslatorInterface && !$translator instanceof LegacyTranslatorInterface) { |
|
79 | 1 | throw new \InvalidArgumentException(sprintf('The "$translator" parameter should be instance of "%s" or "%s"', TranslatorInterface::class, LegacyTranslatorInterface::class)); |
|
80 | } |
||
81 | |||
82 | 8 | $this->translator = $translator; |
|
83 | |||
84 | 8 | $this->webserviceUrl = $this->container->getParameter('version_checker.url'); |
|
85 | 8 | $this->cacheTimeframe = $this->container->getParameter('version_checker.timeframe'); |
|
86 | 8 | $this->enabled = $this->container->getParameter('version_checker.enabled'); |
|
87 | 8 | } |
|
88 | |||
89 | /** |
||
90 | * Check that the version check is enabled. |
||
91 | * |
||
92 | * @return bool |
||
93 | */ |
||
94 | 7 | public function isEnabled() |
|
95 | { |
||
96 | 7 | return $this->enabled; |
|
97 | } |
||
98 | |||
99 | /** |
||
100 | * Check if we recently did a version check, if not do one now. |
||
101 | * |
||
102 | * @throws ParseException |
||
103 | */ |
||
104 | 1 | public function periodicallyCheck() |
|
105 | { |
||
106 | 1 | if (!$this->isEnabled()) { |
|
107 | return; |
||
108 | } |
||
109 | |||
110 | 1 | $cacheItem = $this->cache->getItem(self::CACHE_KEY); |
|
111 | 1 | if (!$cacheItem->isHit() || !\is_array($cacheItem->get())) { |
|
112 | $this->check(); |
||
113 | } |
||
114 | 1 | } |
|
115 | |||
116 | /** |
||
117 | * Get the version details via webservice. |
||
118 | * |
||
119 | * @return mixed a list of bundles if available |
||
120 | * |
||
121 | * @throws ParseException |
||
122 | */ |
||
123 | 5 | public function check() |
|
124 | { |
||
125 | 5 | if (!$this->isEnabled()) { |
|
126 | return; |
||
127 | } |
||
128 | |||
129 | 5 | $host = $this->container->get('request_stack')->getCurrentRequest()->getHttpHost(); |
|
130 | 5 | $console = realpath($this->container->get('kernel')->getProjectDir().'/bin/console'); |
|
131 | 5 | $installed = filectime($console); |
|
132 | 5 | $bundles = $this->parseComposer(); |
|
133 | 2 | $title = $this->container->getParameter('kunstmaan_admin.website_title'); |
|
134 | |||
135 | 2 | $jsonData = json_encode(array( |
|
136 | 2 | 'host' => $host, |
|
137 | 2 | 'installed' => $installed, |
|
138 | 2 | 'bundles' => $bundles, |
|
139 | 2 | 'project' => $this->translator->trans($title), |
|
140 | )); |
||
141 | |||
142 | try { |
||
143 | 2 | $client = $this->getClient(); |
|
144 | 2 | $response = $client->post($this->webserviceUrl, ['body' => $jsonData]); |
|
145 | 1 | $contents = $response->getBody()->getContents(); |
|
146 | 1 | $data = json_decode($contents); |
|
147 | |||
148 | 1 | if (null === $data) { |
|
149 | return false; |
||
150 | } |
||
151 | |||
152 | // Save the result in the cache to make sure we don't do the check too often |
||
153 | 1 | $cacheItem = $this->cache->getItem(self::CACHE_KEY); |
|
154 | 1 | $cacheItem->expiresAfter($this->cacheTimeframe); |
|
155 | 1 | $cacheItem->set($data); |
|
156 | |||
157 | 1 | $this->cache->save($cacheItem); |
|
158 | |||
159 | 1 | return $data; |
|
160 | 1 | } catch (Exception $e) { |
|
161 | // We did not receive valid json |
||
162 | 1 | return false; |
|
163 | } |
||
164 | } |
||
165 | |||
166 | /** |
||
167 | * @return Client |
||
168 | */ |
||
169 | 1 | public function getClient() |
|
170 | { |
||
171 | 1 | if (!$this->client) { |
|
172 | 1 | $this->client = new Client(array('connect_timeout' => 3, 'timeout' => 1)); |
|
173 | } |
||
174 | |||
175 | 1 | return $this->client; |
|
176 | } |
||
177 | |||
178 | /** |
||
179 | * @param Client $client |
||
180 | */ |
||
181 | public function setClient($client) |
||
182 | { |
||
183 | $this->client = $client; |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Returns the absolute path to the composer.lock file. |
||
188 | * |
||
189 | * @return string |
||
190 | */ |
||
191 | protected function getLockPath() |
||
192 | { |
||
193 | $kernel = $this->container->get('kernel'); |
||
194 | $rootPath = $kernel->getProjectDir(); |
||
195 | |||
196 | return $rootPath.'/composer.lock'; |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * Returns a list of composer packages. |
||
201 | * |
||
202 | * @return array |
||
203 | * |
||
204 | * @throws ParseException |
||
205 | */ |
||
206 | 4 | protected function getPackages() |
|
207 | { |
||
208 | 4 | $translator = $this->container->get('translator'); |
|
209 | 4 | $errorMessage = $translator->trans('settings.version.error_parsing_composer'); |
|
210 | |||
211 | 4 | $composerPath = $this->getLockPath(); |
|
212 | 4 | if (!file_exists($composerPath)) { |
|
213 | 1 | throw new ParseException($translator->trans('settings.version.composer_lock_not_found')); |
|
214 | } |
||
215 | |||
216 | 3 | $json = file_get_contents($composerPath); |
|
217 | 3 | $result = json_decode($json, true); |
|
218 | |||
219 | 3 | if (json_last_error() !== JSON_ERROR_NONE) { |
|
220 | 1 | throw new ParseException($errorMessage.' (#'.json_last_error().')'); |
|
221 | } |
||
222 | |||
223 | 2 | if (\array_key_exists('packages', $result) && \is_array($result['packages'])) { |
|
224 | 1 | return $result['packages']; |
|
225 | } |
||
226 | |||
227 | // No package list in JSON structure |
||
228 | 1 | throw new ParseException($errorMessage); |
|
229 | } |
||
230 | |||
231 | /** |
||
232 | * Parse the composer.lock file to get the currently used versions of the kunstmaan bundles. |
||
233 | * |
||
234 | * @return array |
||
235 | * |
||
236 | * @throws ParseException |
||
237 | */ |
||
238 | 4 | protected function parseComposer() |
|
239 | { |
||
240 | 4 | $bundles = array(); |
|
241 | 4 | foreach ($this->getPackages() as $package) { |
|
242 | 1 | if (!strncmp($package['name'], 'kunstmaan/', \strlen('kunstmaan/'))) { |
|
243 | 1 | $bundles[] = array( |
|
244 | 1 | 'name' => $package['name'], |
|
245 | 1 | 'version' => $package['version'], |
|
246 | 1 | 'reference' => $package['source']['reference'], |
|
247 | ); |
||
248 | } |
||
249 | } |
||
250 | |||
251 | 1 | return $bundles; |
|
252 | } |
||
253 | } |
||
254 |
If you suppress an error, we recommend checking for the error condition explicitly: