[Runtime] make GenericRuntime ... generic
This commit is contained in:
parent
49d23d4813
commit
33e371e24d
@ -38,6 +38,8 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
|
|||||||
use Symfony\Component\HttpKernel\KernelEvents;
|
use Symfony\Component\HttpKernel\KernelEvents;
|
||||||
use Symfony\Component\HttpKernel\KernelInterface;
|
use Symfony\Component\HttpKernel\KernelInterface;
|
||||||
use Symfony\Component\HttpKernel\UriSigner;
|
use Symfony\Component\HttpKernel\UriSigner;
|
||||||
|
use Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner;
|
||||||
|
use Symfony\Component\Runtime\Runner\Symfony\ResponseRunner;
|
||||||
use Symfony\Component\Runtime\SymfonyRuntime;
|
use Symfony\Component\Runtime\SymfonyRuntime;
|
||||||
use Symfony\Component\String\LazyString;
|
use Symfony\Component\String\LazyString;
|
||||||
use Symfony\Component\String\Slugger\AsciiSlugger;
|
use Symfony\Component\String\Slugger\AsciiSlugger;
|
||||||
@ -79,6 +81,8 @@ return static function (ContainerConfigurator $container) {
|
|||||||
service('argument_resolver'),
|
service('argument_resolver'),
|
||||||
])
|
])
|
||||||
->tag('container.hot_path')
|
->tag('container.hot_path')
|
||||||
|
->tag('container.preload', ['class' => HttpKernelRunner::class])
|
||||||
|
->tag('container.preload', ['class' => ResponseRunner::class])
|
||||||
->tag('container.preload', ['class' => SymfonyRuntime::class])
|
->tag('container.preload', ['class' => SymfonyRuntime::class])
|
||||||
->alias(HttpKernelInterface::class, 'http_kernel')
|
->alias(HttpKernelInterface::class, 'http_kernel')
|
||||||
|
|
||||||
|
@ -22,8 +22,12 @@ class_exists(ClosureResolver::class);
|
|||||||
/**
|
/**
|
||||||
* A runtime to do bare-metal PHP without using superglobals.
|
* A runtime to do bare-metal PHP without using superglobals.
|
||||||
*
|
*
|
||||||
* One option named "debug" is supported; it toggles displaying errors
|
* It supports the following options:
|
||||||
* and defaults to the "APP_ENV" environment variable.
|
* - "debug" toggles displaying errors and defaults
|
||||||
|
* to the "APP_DEBUG" environment variable;
|
||||||
|
* - "runtimes" maps types to a GenericRuntime implementation
|
||||||
|
* that knows how to deal with each of them;
|
||||||
|
* - "error_handler" defines the class to use to handle PHP errors.
|
||||||
*
|
*
|
||||||
* The app-callable can declare arguments among either:
|
* The app-callable can declare arguments among either:
|
||||||
* - "array $context" to get a local array similar to $_SERVER;
|
* - "array $context" to get a local array similar to $_SERVER;
|
||||||
@ -42,42 +46,48 @@ class_exists(ClosureResolver::class);
|
|||||||
*/
|
*/
|
||||||
class GenericRuntime implements RuntimeInterface
|
class GenericRuntime implements RuntimeInterface
|
||||||
{
|
{
|
||||||
private $debug;
|
protected $options;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array {
|
* @param array {
|
||||||
* debug?: ?bool,
|
* debug?: ?bool,
|
||||||
|
* runtimes?: ?array,
|
||||||
|
* error_handler?: string|false,
|
||||||
* } $options
|
* } $options
|
||||||
*/
|
*/
|
||||||
public function __construct(array $options = [])
|
public function __construct(array $options = [])
|
||||||
{
|
{
|
||||||
$this->debug = $options['debug'] ?? $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? true;
|
$debug = $options['debug'] ?? $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? true;
|
||||||
|
|
||||||
if (!\is_bool($this->debug)) {
|
if (!\is_bool($debug)) {
|
||||||
$this->debug = filter_var($this->debug, \FILTER_VALIDATE_BOOLEAN);
|
$debug = filter_var($debug, \FILTER_VALIDATE_BOOLEAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->debug) {
|
if ($debug) {
|
||||||
|
umask(0000);
|
||||||
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '1';
|
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '1';
|
||||||
$errorHandler = new BasicErrorHandler($this->debug);
|
|
||||||
set_error_handler($errorHandler);
|
if (false !== $errorHandler = ($options['error_handler'] ?? BasicErrorHandler::class)) {
|
||||||
|
$errorHandler::register($debug);
|
||||||
|
$options['error_handler'] = false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0';
|
$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->options = $options;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritdoc}
|
* {@inheritdoc}
|
||||||
*/
|
*/
|
||||||
public function getResolver(callable $callable): ResolverInterface
|
public function getResolver(callable $callable, \ReflectionFunction $reflector = null): ResolverInterface
|
||||||
{
|
{
|
||||||
if (!$callable instanceof \Closure) {
|
if (!$callable instanceof \Closure) {
|
||||||
$callable = \Closure::fromCallable($callable);
|
$callable = \Closure::fromCallable($callable);
|
||||||
}
|
}
|
||||||
|
|
||||||
$function = new \ReflectionFunction($callable);
|
$parameters = ($reflector ?? new \ReflectionFunction($callable))->getParameters();
|
||||||
$parameters = $function->getParameters();
|
|
||||||
|
|
||||||
$arguments = function () use ($parameters) {
|
$arguments = function () use ($parameters) {
|
||||||
$arguments = [];
|
$arguments = [];
|
||||||
|
|
||||||
@ -95,7 +105,7 @@ class GenericRuntime implements RuntimeInterface
|
|||||||
return $arguments;
|
return $arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
if ($this->debug) {
|
if ($_SERVER['APP_DEBUG']) {
|
||||||
return new DebugClosureResolver($callable, $arguments);
|
return new DebugClosureResolver($callable, $arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,15 +125,19 @@ class GenericRuntime implements RuntimeInterface
|
|||||||
return $application;
|
return $application;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$application instanceof \Closure) {
|
||||||
|
if ($runtime = $this->resolveRuntime(\get_class($application))) {
|
||||||
|
return $runtime->getRunner($application);
|
||||||
|
}
|
||||||
|
|
||||||
if (!\is_callable($application)) {
|
if (!\is_callable($application)) {
|
||||||
throw new \LogicException(sprintf('"%s" doesn\'t know how to handle apps of type "%s".', get_debug_type($this), get_debug_type($application)));
|
throw new \LogicException(sprintf('"%s" doesn\'t know how to handle apps of type "%s".', get_debug_type($this), get_debug_type($application)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$application instanceof \Closure) {
|
|
||||||
$application = \Closure::fromCallable($application);
|
$application = \Closure::fromCallable($application);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->debug && ($r = new \ReflectionFunction($application)) && $r->getNumberOfRequiredParameters()) {
|
if ($_SERVER['APP_DEBUG'] && ($r = new \ReflectionFunction($application)) && $r->getNumberOfRequiredParameters()) {
|
||||||
throw new \ArgumentCountError(sprintf('Zero argument should be required by the runner callable, but at least one is in "%s" on line "%d.', $r->getFileName(), $r->getStartLine()));
|
throw new \ArgumentCountError(sprintf('Zero argument should be required by the runner callable, but at least one is in "%s" on line "%d.', $r->getFileName(), $r->getStartLine()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,8 +177,56 @@ class GenericRuntime implements RuntimeInterface
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$runtime = $this->getRuntime($type)) {
|
||||||
$r = $parameter->getDeclaringFunction();
|
$r = $parameter->getDeclaringFunction();
|
||||||
|
|
||||||
throw new \InvalidArgumentException(sprintf('Cannot resolve argument "%s $%s" in "%s" on line "%d": "%s" supports only arguments "array $context", "array $argv" and "array $request".', $type, $parameter->name, $r->getFileName(), $r->getStartLine(), get_debug_type($this)));
|
throw new \InvalidArgumentException(sprintf('Cannot resolve argument "%s $%s" in "%s" on line "%d": "%s" supports only arguments "array $context", "array $argv" and "array $request", or a runtime named "Symfony\Runtime\%1$sRuntime".', $type, $parameter->name, $r->getFileName(), $r->getStartLine(), get_debug_type($this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $runtime->getArgument($parameter, $type);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static function register(self $runtime): self
|
||||||
|
{
|
||||||
|
return $runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getRuntime(string $type): ?self
|
||||||
|
{
|
||||||
|
if (null === $runtime = ($this->options['runtimes'][$type] ?? null)) {
|
||||||
|
$runtime = 'Symfony\Runtime\\'.$type.'Runtime';
|
||||||
|
$runtime = class_exists($runtime) ? $runtime : $this->options['runtimes'][$type] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_string($runtime)) {
|
||||||
|
$runtime = $runtime::register($this);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this === $runtime) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $runtime ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveRuntime(string $class): ?self
|
||||||
|
{
|
||||||
|
if ($runtime = $this->getRuntime($class)) {
|
||||||
|
return $runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (class_parents($class) as $type) {
|
||||||
|
if ($runtime = $this->getRuntime($type)) {
|
||||||
|
return $runtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (class_implements($class) as $type) {
|
||||||
|
if ($runtime = $this->getRuntime($type)) {
|
||||||
|
return $runtime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace Symfony\Component\Runtime\Internal;
|
|||||||
*/
|
*/
|
||||||
class BasicErrorHandler
|
class BasicErrorHandler
|
||||||
{
|
{
|
||||||
public function __construct(bool $debug)
|
public static function register(bool $debug): void
|
||||||
{
|
{
|
||||||
error_reporting(-1);
|
error_reporting(-1);
|
||||||
|
|
||||||
@ -32,10 +32,11 @@ class BasicErrorHandler
|
|||||||
if (0 <= ini_get('zend.assertions')) {
|
if (0 <= ini_get('zend.assertions')) {
|
||||||
ini_set('zend.assertions', 1);
|
ini_set('zend.assertions', 1);
|
||||||
ini_set('assert.active', $debug);
|
ini_set('assert.active', $debug);
|
||||||
ini_set('assert.bail', 0);
|
|
||||||
ini_set('assert.warning', 0);
|
ini_set('assert.warning', 0);
|
||||||
ini_set('assert.exception', 1);
|
ini_set('assert.exception', 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_error_handler(new self());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __invoke(int $type, string $message, string $file, int $line): bool
|
public function __invoke(int $type, string $message, string $file, int $line): bool
|
||||||
|
@ -102,14 +102,12 @@ class ComposerPlugin implements PluginInterface, EventSubscriberInterface
|
|||||||
throw new \InvalidArgumentException(sprintf('Class "%s" listed under "extra.runtime.class" in your composer.json file '.(class_exists($runtimeClass) ? 'should implement "%s".' : 'not found.'), $runtimeClass, RuntimeInterface::class));
|
throw new \InvalidArgumentException(sprintf('Class "%s" listed under "extra.runtime.class" in your composer.json file '.(class_exists($runtimeClass) ? 'should implement "%s".' : 'not found.'), $runtimeClass, RuntimeInterface::class));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!\is_array($runtimeOptions = $extra['options'] ?? [])) {
|
unset($extra['class'], $extra['autoload_template']);
|
||||||
throw new \InvalidArgumentException('The "extra.runtime.options" entry in your composer.json file must be an array.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$code = strtr(file_get_contents($autoloadTemplate), [
|
$code = strtr(file_get_contents($autoloadTemplate), [
|
||||||
'%project_dir%' => $projectDir,
|
'%project_dir%' => $projectDir,
|
||||||
'%runtime_class%' => var_export($runtimeClass, true),
|
'%runtime_class%' => var_export($runtimeClass, true),
|
||||||
'%runtime_options%' => '['.substr(var_export($runtimeOptions, true), 7, -1)." 'project_dir' => {$projectDir},\n]",
|
'%runtime_options%' => '['.substr(var_export($extra, true), 7, -1)." 'project_dir' => {$projectDir},\n]",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
file_put_contents(substr_replace($autoloadFile, '_runtime', -4, 0), $code);
|
file_put_contents(substr_replace($autoloadFile, '_runtime', -4, 0), $code);
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Runtime\Symfony\Component\Console;
|
||||||
|
|
||||||
|
use Symfony\Component\Runtime\SymfonyRuntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class ApplicationRuntime extends SymfonyRuntime
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Runtime\Symfony\Component\Console\Command;
|
||||||
|
|
||||||
|
use Symfony\Component\Runtime\SymfonyRuntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class CommandRuntime extends SymfonyRuntime
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Runtime\Symfony\Component\Console\Input;
|
||||||
|
|
||||||
|
use Symfony\Component\Runtime\SymfonyRuntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class InputInterfaceRuntime extends SymfonyRuntime
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Runtime\Symfony\Component\Console\Output;
|
||||||
|
|
||||||
|
use Symfony\Component\Runtime\SymfonyRuntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class OutputInterfaceRuntime extends SymfonyRuntime
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Runtime\Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
use Symfony\Component\Runtime\SymfonyRuntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class RequestRuntime extends SymfonyRuntime
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Runtime\Symfony\Component\HttpFoundation;
|
||||||
|
|
||||||
|
use Symfony\Component\Runtime\SymfonyRuntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class ResponseRuntime extends SymfonyRuntime
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Runtime\Symfony\Component\HttKernel;
|
||||||
|
|
||||||
|
use Symfony\Component\Runtime\SymfonyRuntime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class HttpKernelInterfaceRuntime extends SymfonyRuntime
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the Symfony package.
|
||||||
|
*
|
||||||
|
* (c) Fabien Potencier <fabien@symfony.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Symfony\Component\Runtime\Internal;
|
||||||
|
|
||||||
|
use Symfony\Component\ErrorHandler\BufferingLogger;
|
||||||
|
use Symfony\Component\ErrorHandler\DebugClassLoader;
|
||||||
|
use Symfony\Component\ErrorHandler\ErrorHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nicolas Grekas <p@tchwork.com>
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
class SymfonyErrorHandler
|
||||||
|
{
|
||||||
|
public static function register(bool $debug): void
|
||||||
|
{
|
||||||
|
BasicErrorHandler::register($debug);
|
||||||
|
|
||||||
|
if (class_exists(ErrorHandler::class)) {
|
||||||
|
DebugClassLoader::enable();
|
||||||
|
restore_error_handler();
|
||||||
|
ErrorHandler::register(new ErrorHandler(new BufferingLogger(), true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,7 @@ interface RuntimeInterface
|
|||||||
*
|
*
|
||||||
* The callable itself should return an object that represents the application to pass to the getRunner() method.
|
* The callable itself should return an object that represents the application to pass to the getRunner() method.
|
||||||
*/
|
*/
|
||||||
public function getResolver(callable $callable): ResolverInterface;
|
public function getResolver(callable $callable, \ReflectionFunction $reflector = null): ResolverInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a callable that knows how to run the passed object and that returns its exit status as int.
|
* Returns a callable that knows how to run the passed object and that returns its exit status as int.
|
||||||
|
@ -18,38 +18,35 @@ use Symfony\Component\Console\Input\InputInterface;
|
|||||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
use Symfony\Component\Dotenv\Dotenv;
|
use Symfony\Component\Dotenv\Dotenv;
|
||||||
use Symfony\Component\ErrorHandler\Debug;
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||||
use Symfony\Component\Runtime\Internal\MissingDotenv;
|
use Symfony\Component\Runtime\Internal\MissingDotenv;
|
||||||
|
use Symfony\Component\Runtime\Internal\SymfonyErrorHandler;
|
||||||
use Symfony\Component\Runtime\Runner\Symfony\ConsoleApplicationRunner;
|
use Symfony\Component\Runtime\Runner\Symfony\ConsoleApplicationRunner;
|
||||||
use Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner;
|
use Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner;
|
||||||
use Symfony\Component\Runtime\Runner\Symfony\ResponseRunner;
|
use Symfony\Component\Runtime\Runner\Symfony\ResponseRunner;
|
||||||
|
|
||||||
// Help opcache.preload discover always-needed symbols
|
// Help opcache.preload discover always-needed symbols
|
||||||
class_exists(ResponseRunner::class);
|
|
||||||
class_exists(HttpKernelRunner::class);
|
|
||||||
class_exists(MissingDotenv::class, false) || class_exists(Dotenv::class) || class_exists(MissingDotenv::class);
|
class_exists(MissingDotenv::class, false) || class_exists(Dotenv::class) || class_exists(MissingDotenv::class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Knows the basic conventions to run Symfony apps.
|
* Knows the basic conventions to run Symfony apps.
|
||||||
*
|
*
|
||||||
* Accepts the following options:
|
* In addition to the options managed by GenericRuntime, it accepts the following options:
|
||||||
* - "debug" to toggle debugging features
|
* - "env" to define the name of the environment the app runs in;
|
||||||
* - "env" to define the name of the environment the app runs in
|
* - "disable_dotenv" to disable looking for .env files;
|
||||||
* - "disable_dotenv" to disable looking for .env files
|
* - "dotenv_path" to define the path of dot-env files - defaults to ".env";
|
||||||
* - "dotenv_path" to define the path of dot-env files - defaults to ".env"
|
* - "prod_envs" to define the names of the production envs - defaults to ["prod"];
|
||||||
* - "prod_envs" to define the names of the production envs - defaults to ["prod"]
|
* - "test_envs" to define the names of the test envs - defaults to ["test"];
|
||||||
* - "test_envs" to define the names of the test envs - defaults to ["test"]
|
* - "use_putenv" to tell Dotenv to set env vars using putenv() (NOT RECOMMENDED.)
|
||||||
*
|
*
|
||||||
* When these options are not defined, they will fallback:
|
* When the "debug" / "env" options are not defined, they will fallback to the
|
||||||
* - to reading the "APP_DEBUG" and "APP_ENV" environment variables;
|
* "APP_DEBUG" / "APP_ENV" environment variables, and to the "--env|-e" / "--no-debug"
|
||||||
* - to parsing the "--env|-e" and "--no-debug" command line arguments
|
* command line arguments if "symfony/console" is installed.
|
||||||
* if the "symfony/console" component is installed.
|
|
||||||
*
|
*
|
||||||
* When the "symfony/dotenv" component is installed, .env files are loaded.
|
* When the "symfony/dotenv" component is installed, .env files are loaded.
|
||||||
* When "symfony/error-handler" is installed, it is registred in debug mode.
|
* When "symfony/error-handler" is installed, it is registered in debug mode.
|
||||||
*
|
*
|
||||||
* On top of the base arguments provided by GenericRuntime,
|
* On top of the base arguments provided by GenericRuntime,
|
||||||
* this runtime can feed the app-callable with arguments of type:
|
* this runtime can feed the app-callable with arguments of type:
|
||||||
@ -74,7 +71,6 @@ class SymfonyRuntime extends GenericRuntime
|
|||||||
private $output;
|
private $output;
|
||||||
private $console;
|
private $console;
|
||||||
private $command;
|
private $command;
|
||||||
private $env;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array {
|
* @param array {
|
||||||
@ -85,31 +81,32 @@ class SymfonyRuntime extends GenericRuntime
|
|||||||
* prod_envs?: ?string[],
|
* prod_envs?: ?string[],
|
||||||
* dotenv_path?: ?string,
|
* dotenv_path?: ?string,
|
||||||
* test_envs?: ?string[],
|
* test_envs?: ?string[],
|
||||||
|
* use_putenv?: ?bool,
|
||||||
|
* runtimes?: ?array,
|
||||||
|
* error_handler?: string|false,
|
||||||
* } $options
|
* } $options
|
||||||
*/
|
*/
|
||||||
public function __construct(array $options = [])
|
public function __construct(array $options = [])
|
||||||
{
|
{
|
||||||
$this->env = $options['env'] ?? null;
|
if (isset($_SERVER['argv']) && !isset($options['env']) && class_exists(ArgvInput::class)) {
|
||||||
$_SERVER['APP_ENV'] = $options['env'] ?? $_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null;
|
$this->options = $options;
|
||||||
|
|
||||||
if (isset($_SERVER['argv']) && null === $this->env && class_exists(ArgvInput::class)) {
|
|
||||||
$this->getInput();
|
$this->getInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$_SERVER['APP_ENV'] = $options['env'] ?? $_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? 'dev';
|
||||||
|
|
||||||
if (!($options['disable_dotenv'] ?? false) && isset($options['project_dir']) && !class_exists(MissingDotenv::class, false)) {
|
if (!($options['disable_dotenv'] ?? false) && isset($options['project_dir']) && !class_exists(MissingDotenv::class, false)) {
|
||||||
(new Dotenv())
|
(new Dotenv())
|
||||||
->setProdEnvs((array) ($options['prod_envs'] ?? ['prod']))
|
->setProdEnvs((array) ($options['prod_envs'] ?? ['prod']))
|
||||||
|
->usePutenv($options['use_putenv'] ?? false)
|
||||||
->bootEnv($options['project_dir'].'/'.($options['dotenv_path'] ?? '.env'), 'dev', (array) ($options['test_envs'] ?? ['test']));
|
->bootEnv($options['project_dir'].'/'.($options['dotenv_path'] ?? '.env'), 'dev', (array) ($options['test_envs'] ?? ['test']));
|
||||||
$options['debug'] ?? $options['debug'] = '1' === $_SERVER['APP_DEBUG'];
|
$options['debug'] ?? $options['debug'] = '1' === $_SERVER['APP_DEBUG'];
|
||||||
|
$options['disable_dotenv'] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$options['error_handler'] ?? $options['error_handler'] = SymfonyErrorHandler::class;
|
||||||
|
|
||||||
parent::__construct($options);
|
parent::__construct($options);
|
||||||
|
|
||||||
if ($_SERVER['APP_DEBUG'] && class_exists(Debug::class)) {
|
|
||||||
restore_error_handler();
|
|
||||||
umask(0000);
|
|
||||||
Debug::enable();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getRunner(?object $application): RunnerInterface
|
public function getRunner(?object $application): RunnerInterface
|
||||||
@ -142,7 +139,7 @@ class SymfonyRuntime extends GenericRuntime
|
|||||||
}
|
}
|
||||||
|
|
||||||
set_time_limit(0);
|
set_time_limit(0);
|
||||||
$defaultEnv = null === $this->env ? ($_SERVER['APP_ENV'] ?? 'dev') : null;
|
$defaultEnv = !isset($this->options['env']) ? ($_SERVER['APP_ENV'] ?? 'dev') : null;
|
||||||
$output = $this->output ?? $this->output = new ConsoleOutput();
|
$output = $this->output ?? $this->output = new ConsoleOutput();
|
||||||
|
|
||||||
return new ConsoleApplicationRunner($application, $defaultEnv, $this->getInput(), $output);
|
return new ConsoleApplicationRunner($application, $defaultEnv, $this->getInput(), $output);
|
||||||
@ -180,6 +177,23 @@ class SymfonyRuntime extends GenericRuntime
|
|||||||
return parent::getArgument($parameter, $type);
|
return parent::getArgument($parameter, $type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static function register(parent $runtime): parent
|
||||||
|
{
|
||||||
|
$self = new self($runtime->options + ['runtimes' => []]);
|
||||||
|
$self->options['runtimes'] += [
|
||||||
|
HttpKernelInterface::class => $self,
|
||||||
|
Request::class => $self,
|
||||||
|
Response::class => $self,
|
||||||
|
Application::class => $self,
|
||||||
|
Command::class => $self,
|
||||||
|
InputInterface::class => $self,
|
||||||
|
OutputInterface::class => $self,
|
||||||
|
];
|
||||||
|
$runtime->options = $self->options;
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
private function getInput(): ArgvInput
|
private function getInput(): ArgvInput
|
||||||
{
|
{
|
||||||
if (null !== $this->input) {
|
if (null !== $this->input) {
|
||||||
@ -188,7 +202,7 @@ class SymfonyRuntime extends GenericRuntime
|
|||||||
|
|
||||||
$input = new ArgvInput();
|
$input = new ArgvInput();
|
||||||
|
|
||||||
if (null !== $this->env) {
|
if (isset($this->options['env'])) {
|
||||||
return $this->input = $input;
|
return $this->input = $input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,8 @@ if (file_exists(dirname(__DIR__, 2).'/vendor/autoload.php')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$app = require $_SERVER['SCRIPT_FILENAME'];
|
$app = require $_SERVER['SCRIPT_FILENAME'];
|
||||||
$runtime = new SymfonyRuntime($_SERVER['APP_RUNTIME_OPTIONS']);
|
$runtime = $_SERVER['APP_RUNTIME'] ?? SymfonyRuntime::class;
|
||||||
|
$runtime = new $runtime($_SERVER['APP_RUNTIME_OPTIONS']);
|
||||||
[$app, $args] = $runtime->getResolver($app)->resolve();
|
[$app, $args] = $runtime->getResolver($app)->resolve();
|
||||||
exit($runtime->getRunner($app(...$args))->run());
|
exit($runtime->getRunner($app(...$args))->run());
|
||||||
}
|
}
|
||||||
|
19
src/Symfony/Component/Runtime/Tests/phpt/generic-request.php
Normal file
19
src/Symfony/Component/Runtime/Tests/phpt/generic-request.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
|
use Symfony\Component\Runtime\GenericRuntime;
|
||||||
|
use Symfony\Runtime\Symfony\Component\HttpFoundation\RequestRuntime;
|
||||||
|
use Symfony\Runtime\Symfony\Component\HttpFoundation\ResponseRuntime;
|
||||||
|
|
||||||
|
$_SERVER['APP_RUNTIME'] = GenericRuntime::class;
|
||||||
|
require __DIR__.'/autoload.php';
|
||||||
|
|
||||||
|
return function (Request $request, array $context) {
|
||||||
|
echo class_exists(RequestRuntime::class, false) ? 'OK request runtime' : 'KO request runtime', "\n";
|
||||||
|
|
||||||
|
return new StreamedResponse(function () use ($context) {
|
||||||
|
echo 'OK Request '.$context['SOME_VAR'], "\n";
|
||||||
|
echo class_exists(ResponseRuntime::class, false) ? 'KO response runtime' : 'OK response runtime', "\n";
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
--TEST--
|
||||||
|
Test Request/Response
|
||||||
|
--INI--
|
||||||
|
display_errors=1
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require $_SERVER['SCRIPT_FILENAME'] = __DIR__.'/generic-request.php';
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
OK request runtime
|
||||||
|
OK Request foo_bar
|
||||||
|
OK response runtime
|
@ -1,9 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\Runtime\SymfonyRuntime;
|
|
||||||
use Symfony\Component\Runtime\Runner\ClosureRunner;
|
use Symfony\Component\Runtime\Runner\ClosureRunner;
|
||||||
use Symfony\Component\Runtime\RunnerInterface;
|
use Symfony\Component\Runtime\RunnerInterface;
|
||||||
|
use Symfony\Component\Runtime\SymfonyRuntime;
|
||||||
|
|
||||||
require __DIR__.'/autoload.php';
|
require __DIR__.'/autoload.php';
|
||||||
|
|
||||||
|
@ -30,7 +30,10 @@
|
|||||||
"symfony/dotenv": "<5.1"
|
"symfony/dotenv": "<5.1"
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-4": { "Symfony\\Component\\Runtime\\": "" },
|
"psr-4": {
|
||||||
|
"Symfony\\Component\\Runtime\\": "",
|
||||||
|
"Symfony\\Runtime\\Symfony\\Component\\": "Internal/"
|
||||||
|
},
|
||||||
"exclude-from-classmap": [
|
"exclude-from-classmap": [
|
||||||
"/Tests/"
|
"/Tests/"
|
||||||
]
|
]
|
||||||
|
Reference in New Issue
Block a user