1<?php
2
3/*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Symfony\Component\HttpKernel\DataCollector;
13
14use Symfony\Component\HttpFoundation\Request;
15use Symfony\Component\HttpFoundation\Response;
16use Symfony\Component\HttpKernel\Kernel;
17use Symfony\Component\HttpKernel\KernelInterface;
18use Symfony\Component\VarDumper\Caster\ClassStub;
19
20/**
21 * @author Fabien Potencier <fabien@symfony.com>
22 *
23 * @final since Symfony 4.4
24 */
25class ConfigDataCollector extends DataCollector implements LateDataCollectorInterface
26{
27    /**
28     * @var KernelInterface
29     */
30    private $kernel;
31    private $name;
32    private $version;
33
34    public function __construct(string $name = null, string $version = null)
35    {
36        if (1 <= \func_num_args()) {
37            @trigger_error(sprintf('The "$name" argument in method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
38        }
39        if (2 <= \func_num_args()) {
40            @trigger_error(sprintf('The "$version" argument in method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
41        }
42
43        $this->name = $name;
44        $this->version = $version;
45    }
46
47    /**
48     * Sets the Kernel associated with this Request.
49     */
50    public function setKernel(KernelInterface $kernel = null)
51    {
52        $this->kernel = $kernel;
53    }
54
55    /**
56     * {@inheritdoc}
57     *
58     * @param \Throwable|null $exception
59     */
60    public function collect(Request $request, Response $response/*, \Throwable $exception = null*/)
61    {
62        $this->data = [
63            'app_name' => $this->name,
64            'app_version' => $this->version,
65            'token' => $response->headers->get('X-Debug-Token'),
66            'symfony_version' => Kernel::VERSION,
67            'symfony_state' => 'unknown',
68            'env' => isset($this->kernel) ? $this->kernel->getEnvironment() : 'n/a',
69            'debug' => isset($this->kernel) ? $this->kernel->isDebug() : 'n/a',
70            'php_version' => PHP_VERSION,
71            'php_architecture' => PHP_INT_SIZE * 8,
72            'php_intl_locale' => class_exists('Locale', false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a',
73            'php_timezone' => date_default_timezone_get(),
74            'xdebug_enabled' => \extension_loaded('xdebug'),
75            'apcu_enabled' => \extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN),
76            'zend_opcache_enabled' => \extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN),
77            'bundles' => [],
78            'sapi_name' => \PHP_SAPI,
79        ];
80
81        if (isset($this->kernel)) {
82            foreach ($this->kernel->getBundles() as $name => $bundle) {
83                $this->data['bundles'][$name] = new ClassStub(\get_class($bundle));
84            }
85
86            $this->data['symfony_state'] = $this->determineSymfonyState();
87            $this->data['symfony_minor_version'] = sprintf('%s.%s', Kernel::MAJOR_VERSION, Kernel::MINOR_VERSION);
88            $this->data['symfony_lts'] = 4 === Kernel::MINOR_VERSION;
89            $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE);
90            $eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE);
91            $this->data['symfony_eom'] = $eom->format('F Y');
92            $this->data['symfony_eol'] = $eol->format('F Y');
93        }
94
95        if (preg_match('~^(\d+(?:\.\d+)*)(.+)?$~', $this->data['php_version'], $matches) && isset($matches[2])) {
96            $this->data['php_version'] = $matches[1];
97            $this->data['php_version_extra'] = $matches[2];
98        }
99    }
100
101    /**
102     * {@inheritdoc}
103     */
104    public function reset()
105    {
106        $this->data = [];
107    }
108
109    public function lateCollect()
110    {
111        $this->data = $this->cloneVar($this->data);
112    }
113
114    /**
115     * @deprecated since Symfony 4.2
116     */
117    public function getApplicationName()
118    {
119        @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
120
121        return $this->data['app_name'];
122    }
123
124    /**
125     * @deprecated since Symfony 4.2
126     */
127    public function getApplicationVersion()
128    {
129        @trigger_error(sprintf('The method "%s()" is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
130
131        return $this->data['app_version'];
132    }
133
134    /**
135     * Gets the token.
136     *
137     * @return string|null The token
138     */
139    public function getToken()
140    {
141        return $this->data['token'];
142    }
143
144    /**
145     * Gets the Symfony version.
146     *
147     * @return string The Symfony version
148     */
149    public function getSymfonyVersion()
150    {
151        return $this->data['symfony_version'];
152    }
153
154    /**
155     * Returns the state of the current Symfony release.
156     *
157     * @return string One of: unknown, dev, stable, eom, eol
158     */
159    public function getSymfonyState()
160    {
161        return $this->data['symfony_state'];
162    }
163
164    /**
165     * Returns the minor Symfony version used (without patch numbers of extra
166     * suffix like "RC", "beta", etc.).
167     *
168     * @return string
169     */
170    public function getSymfonyMinorVersion()
171    {
172        return $this->data['symfony_minor_version'];
173    }
174
175    /**
176     * Returns if the current Symfony version is a Long-Term Support one.
177     */
178    public function isSymfonyLts(): bool
179    {
180        return $this->data['symfony_lts'];
181    }
182
183    /**
184     * Returns the human redable date when this Symfony version ends its
185     * maintenance period.
186     *
187     * @return string
188     */
189    public function getSymfonyEom()
190    {
191        return $this->data['symfony_eom'];
192    }
193
194    /**
195     * Returns the human redable date when this Symfony version reaches its
196     * "end of life" and won't receive bugs or security fixes.
197     *
198     * @return string
199     */
200    public function getSymfonyEol()
201    {
202        return $this->data['symfony_eol'];
203    }
204
205    /**
206     * Gets the PHP version.
207     *
208     * @return string The PHP version
209     */
210    public function getPhpVersion()
211    {
212        return $this->data['php_version'];
213    }
214
215    /**
216     * Gets the PHP version extra part.
217     *
218     * @return string|null The extra part
219     */
220    public function getPhpVersionExtra()
221    {
222        return isset($this->data['php_version_extra']) ? $this->data['php_version_extra'] : null;
223    }
224
225    /**
226     * @return int The PHP architecture as number of bits (e.g. 32 or 64)
227     */
228    public function getPhpArchitecture()
229    {
230        return $this->data['php_architecture'];
231    }
232
233    /**
234     * @return string
235     */
236    public function getPhpIntlLocale()
237    {
238        return $this->data['php_intl_locale'];
239    }
240
241    /**
242     * @return string
243     */
244    public function getPhpTimezone()
245    {
246        return $this->data['php_timezone'];
247    }
248
249    /**
250     * Gets the application name.
251     *
252     * @return string The application name
253     *
254     * @deprecated since Symfony 4.2
255     */
256    public function getAppName()
257    {
258        @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2.', __METHOD__), E_USER_DEPRECATED);
259
260        return 'n/a';
261    }
262
263    /**
264     * Gets the environment.
265     *
266     * @return string The environment
267     */
268    public function getEnv()
269    {
270        return $this->data['env'];
271    }
272
273    /**
274     * Returns true if the debug is enabled.
275     *
276     * @return bool true if debug is enabled, false otherwise
277     */
278    public function isDebug()
279    {
280        return $this->data['debug'];
281    }
282
283    /**
284     * Returns true if the XDebug is enabled.
285     *
286     * @return bool true if XDebug is enabled, false otherwise
287     */
288    public function hasXDebug()
289    {
290        return $this->data['xdebug_enabled'];
291    }
292
293    /**
294     * Returns true if APCu is enabled.
295     *
296     * @return bool true if APCu is enabled, false otherwise
297     */
298    public function hasApcu()
299    {
300        return $this->data['apcu_enabled'];
301    }
302
303    /**
304     * Returns true if Zend OPcache is enabled.
305     *
306     * @return bool true if Zend OPcache is enabled, false otherwise
307     */
308    public function hasZendOpcache()
309    {
310        return $this->data['zend_opcache_enabled'];
311    }
312
313    public function getBundles()
314    {
315        return $this->data['bundles'];
316    }
317
318    /**
319     * Gets the PHP SAPI name.
320     *
321     * @return string The environment
322     */
323    public function getSapiName()
324    {
325        return $this->data['sapi_name'];
326    }
327
328    /**
329     * {@inheritdoc}
330     */
331    public function getName()
332    {
333        return 'config';
334    }
335
336    /**
337     * Tries to retrieve information about the current Symfony version.
338     *
339     * @return string One of: dev, stable, eom, eol
340     */
341    private function determineSymfonyState(): string
342    {
343        $now = new \DateTime();
344        $eom = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_MAINTENANCE)->modify('last day of this month');
345        $eol = \DateTime::createFromFormat('d/m/Y', '01/'.Kernel::END_OF_LIFE)->modify('last day of this month');
346
347        if ($now > $eol) {
348            $versionState = 'eol';
349        } elseif ($now > $eom) {
350            $versionState = 'eom';
351        } elseif ('' !== Kernel::EXTRA_VERSION) {
352            $versionState = 'dev';
353        } else {
354            $versionState = 'stable';
355        }
356
357        return $versionState;
358    }
359}
360