initial commit
This commit is contained in:
743
vendor/symfony/framework-bundle/CHANGELOG.md
vendored
Normal file
743
vendor/symfony/framework-bundle/CHANGELOG.md
vendored
Normal file
@@ -0,0 +1,743 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
7.3
|
||||
---
|
||||
|
||||
* Add `errors.php` and `webhook.php` routing configuration files (use them instead of their XML equivalent)
|
||||
|
||||
Before:
|
||||
|
||||
```yaml
|
||||
when@dev:
|
||||
_errors:
|
||||
resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
|
||||
prefix: /_error
|
||||
|
||||
webhook:
|
||||
resource: '@FrameworkBundle/Resources/config/routing/webhook.xml'
|
||||
prefix: /webhook
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```yaml
|
||||
when@dev:
|
||||
_errors:
|
||||
resource: '@FrameworkBundle/Resources/config/routing/errors.php'
|
||||
prefix: /_error
|
||||
|
||||
webhook:
|
||||
resource: '@FrameworkBundle/Resources/config/routing/webhook.php'
|
||||
prefix: /webhook
|
||||
```
|
||||
|
||||
* Add support for the ObjectMapper component
|
||||
* Add support for assets pre-compression
|
||||
* Rename `TranslationUpdateCommand` to `TranslationExtractCommand`
|
||||
* Add JsonStreamer services and configuration
|
||||
* Add new `framework.property_info.with_constructor_extractor` option to allow enabling or disabling the constructor extractor integration
|
||||
* Deprecate the `--show-arguments` option of the `container:debug` command, as arguments are now always shown
|
||||
* Add autowiring alias for `RateLimiterFactoryInterface`
|
||||
* Add `framework.validation.disable_translation` option
|
||||
* Add support for signal plain name in the `messenger.stop_worker_on_signals` configuration
|
||||
* Deprecate the `framework.validation.cache` option
|
||||
* Add `--method` option to the `debug:router` command
|
||||
* Auto-exclude DI extensions, test cases, entities and messenger messages
|
||||
* Add DI alias from `ServicesResetterInterface` to `services_resetter`
|
||||
* Add `methods` argument in `#[IsCsrfTokenValid]` attribute
|
||||
* Allow configuring the logging channel per type of exceptions
|
||||
* Enable service argument resolution on classes that use the `#[Route]` attribute,
|
||||
the `#[AsController]` attribute is no longer required
|
||||
* Deprecate setting the `framework.profiler.collect_serializer_data` config option to `false`
|
||||
* Set `framework.rate_limiter.limiters.*.lock_factory` to `auto` by default
|
||||
* Deprecate `RateLimiterFactory` autowiring aliases, use `RateLimiterFactoryInterface` instead
|
||||
* Allow configuring compound rate limiters
|
||||
* Make `ValidatorCacheWarmer` use `kernel.build_dir` instead of `cache_dir`
|
||||
* Make `SerializeCacheWarmer` use `kernel.build_dir` instead of `cache_dir`
|
||||
* Support executing custom workflow validators during container compilation
|
||||
|
||||
7.2
|
||||
---
|
||||
|
||||
* Add support for `--sort` option when extracting translations with `translation:extract` command and `--force` option
|
||||
* Add support for setting `headers` with `Symfony\Bundle\FrameworkBundle\Controller\TemplateController`
|
||||
* Add `--resolve-env-vars` option to `lint:container` command
|
||||
* Derivate `kernel.secret` from the decryption secret when its env var is not defined
|
||||
* Make the `config/` directory optional in `MicroKernelTrait`, add support for service arguments in the
|
||||
invokable Kernel class, and register `FrameworkBundle` by default when the `bundles.php` file is missing
|
||||
* [BC BREAK] The `secrets:decrypt-to-local` command terminates with a non-zero exit code when a secret could not be read
|
||||
* Deprecate making `cache.app` adapter taggable, use the `cache.app.taggable` adapter instead
|
||||
* Enable `json_decode_detailed_errors` in the default serializer context in debug mode by default when `seld/jsonlint` is installed
|
||||
* Register `Symfony\Component\Serializer\NameConverter\SnakeCaseToCamelCaseNameConverter` as a service named `serializer.name_converter.snake_case_to_camel_case` if available
|
||||
* Add `framework.csrf_protection.stateless_token_ids`, `.cookie_name`, and `.check_header` options to use stateless headers/cookies-based CSRF protection
|
||||
* Add `framework.form.csrf_protection.field_attr` option
|
||||
* Deprecate `session.sid_length` and `session.sid_bits_per_character` config options
|
||||
* Add the ability to use an existing service as a lock/semaphore resource
|
||||
* Add support for configuring multiple serializer instances via the configuration
|
||||
* Add support for `SYMFONY_TRUSTED_PROXIES`, `SYMFONY_TRUSTED_HEADERS`, `SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER` and `SYMFONY_TRUSTED_HOSTS` env vars
|
||||
* Add `--no-fill` option to `translation:extract` command
|
||||
|
||||
7.1
|
||||
---
|
||||
|
||||
* Add `CheckAliasValidityPass` to `lint:container` command
|
||||
* Add `private_ranges` as a shortcut for private IP address ranges to the `trusted_proxies` option
|
||||
* Mark classes `ConfigBuilderCacheWarmer`, `Router`, `SerializerCacheWarmer`, `TranslationsCacheWarmer`, `Translator` and `ValidatorCacheWarmer` as `final`
|
||||
* Move the Router `cache_dir` to `kernel.build_dir`
|
||||
* Deprecate the `router.cache_dir` config option
|
||||
* Add `rate_limiter` tags to rate limiter services
|
||||
* Add `secrets:reveal` command
|
||||
* Add `rate_limiter` option to `http_client.default_options` and `http_client.scoped_clients`
|
||||
* Attach the workflow's configuration to the `workflow` tag
|
||||
* Add the `allowed_recipients` option for mailer to allow some users to receive
|
||||
emails even if `recipients` is defined.
|
||||
* Reset env vars when resetting the container
|
||||
|
||||
7.0
|
||||
---
|
||||
|
||||
* Remove command `translation:update`, use `translation:extract` instead
|
||||
* Make the `http_method_override` config option default to `false`
|
||||
* Remove `AbstractController::renderForm()`, use `render()` instead
|
||||
* Remove the `Symfony\Component\Serializer\Normalizer\ObjectNormalizer` and
|
||||
`Symfony\Component\Serializer\Normalizer\PropertyNormalizer` autowiring aliases, type-hint against
|
||||
`Symfony\Component\Serializer\Normalizer\NormalizerInterface` or implement `NormalizerAwareInterface` instead
|
||||
* Remove the `Http\Client\HttpClient` service, use `Psr\Http\Client\ClientInterface` instead
|
||||
* Remove the integration of Doctrine annotations, use native attributes instead
|
||||
* Remove `EnableLoggerDebugModePass`, use argument `$debug` of HttpKernel's `Logger` instead
|
||||
* Remove `AddDebugLogProcessorPass::configureLogger()`, use HttpKernel's `DebugLoggerConfigurator` instead
|
||||
* Make the `framework.handle_all_throwables` config option default to `true`
|
||||
* Make the `framework.php_errors.log` config option default to `true`
|
||||
* Make the `framework.session.cookie_secure` config option default to `auto`
|
||||
* Make the `framework.session.cookie_samesite` config option default to `lax`
|
||||
* Make the `framework.session.handler_id` default to null if `save_path` is not set and to `session.handler.native_file` otherwise
|
||||
* Make the `framework.uid.default_uuid_version` config option default to `7`
|
||||
* Make the `framework.uid.time_based_uuid_version` config option default to `7`
|
||||
* Make the `framework.validation.email_validation_mode` config option default to `html5`
|
||||
* Remove the `framework.validation.enable_annotations` config option, use `framework.validation.enable_attributes` instead
|
||||
* Remove the `framework.serializer.enable_annotations` config option, use `framework.serializer.enable_attributes` instead
|
||||
* Remove the `routing.loader.annotation` service, use the `routing.loader.attribute` service instead
|
||||
* Remove the `routing.loader.annotation.directory` service, use the `routing.loader.attribute.directory` service instead
|
||||
* Remove the `routing.loader.annotation.file` service, use the `routing.loader.attribute.file` service instead
|
||||
* Remove `AnnotatedRouteControllerLoader`, use `AttributeRouteControllerLoader` instead
|
||||
* Remove `AddExpressionLanguageProvidersPass`, use `Symfony\Component\Routing\DependencyInjection\AddExpressionLanguageProvidersPass` instead
|
||||
* Remove `DataCollectorTranslatorPass`, use `Symfony\Component\Translation\DependencyInjection\DataCollectorTranslatorPass` instead
|
||||
* Remove `LoggingTranslatorPass`, use `Symfony\Component\Translation\DependencyInjection\LoggingTranslatorPass` instead
|
||||
* Remove `WorkflowGuardListenerPass`, use `Symfony\Component\Workflow\DependencyInjection\WorkflowGuardListenerPass` instead
|
||||
|
||||
6.4
|
||||
---
|
||||
|
||||
* Add `HttpClientAssertionsTrait`
|
||||
* Add `AbstractController::renderBlock()` and `renderBlockView()`
|
||||
* Add native return type to `Translator` and to `Application::reset()`
|
||||
* Deprecate the integration of Doctrine annotations, either uninstall the `doctrine/annotations` package or disable the integration by setting `framework.annotations` to `false`
|
||||
* Enable `json_decode_detailed_errors` context for Serializer by default if `kernel.debug` is true and the `seld/jsonlint` package is installed
|
||||
* Add `DomCrawlerAssertionsTrait::assertAnySelectorTextContains(string $selector, string $text)`
|
||||
* Add `DomCrawlerAssertionsTrait::assertAnySelectorTextSame(string $selector, string $text)`
|
||||
* Add `DomCrawlerAssertionsTrait::assertAnySelectorTextNotContains(string $selector, string $text)`
|
||||
* Deprecate `EnableLoggerDebugModePass`, use argument `$debug` of HttpKernel's `Logger` instead
|
||||
* Deprecate `AddDebugLogProcessorPass::configureLogger()`, use HttpKernel's `DebugLoggerConfigurator` instead
|
||||
* Deprecate not setting the `framework.handle_all_throwables` config option; it will default to `true` in 7.0
|
||||
* Deprecate not setting the `framework.php_errors.log` config option; it will default to `true` in 7.0
|
||||
* Deprecate not setting the `framework.session.cookie_secure` config option; it will default to `auto` in 7.0
|
||||
* Deprecate not setting the `framework.session.cookie_samesite` config option; it will default to `lax` in 7.0
|
||||
* Deprecate not setting either `framework.session.handler_id` or `save_path` config options; `handler_id` will
|
||||
default to null in 7.0 if `save_path` is not set and to `session.handler.native_file` otherwise
|
||||
* Deprecate not setting the `framework.uid.default_uuid_version` config option; it will default to `7` in 7.0
|
||||
* Deprecate not setting the `framework.uid.time_based_uuid_version` config option; it will default to `7` in 7.0
|
||||
* Deprecate not setting the `framework.validation.email_validation_mode` config option; it will default to `html5` in 7.0
|
||||
* Deprecate `framework.validation.enable_annotations`, use `framework.validation.enable_attributes` instead
|
||||
* Deprecate `framework.serializer.enable_annotations`, use `framework.serializer.enable_attributes` instead
|
||||
* Add `array $tokenAttributes = []` optional parameter to `KernelBrowser::loginUser()`
|
||||
* Add support for relative URLs in BrowserKit's redirect assertion
|
||||
* Change BrowserKitAssertionsTrait::getClient() to be protected
|
||||
* Deprecate the `framework.asset_mapper.provider` config option
|
||||
* Add `--exclude` option to the `cache:pool:clear` command
|
||||
* Add parameters deprecations to the output of `debug:container` command
|
||||
* Change `framework.asset_mapper.importmap_polyfill` from a URL to the name of an item in the importmap
|
||||
* Provide `$buildDir` when running `CacheWarmer` to build read-only resources
|
||||
* Add the global `--profile` option to the console to enable profiling commands
|
||||
* Deprecate the `routing.loader.annotation` service, use the `routing.loader.attribute` service instead
|
||||
* Deprecate the `routing.loader.annotation.directory` service, use the `routing.loader.attribute.directory` service instead
|
||||
* Deprecate the `routing.loader.annotation.file` service, use the `routing.loader.attribute.file` service instead
|
||||
* Deprecate `AnnotatedRouteControllerLoader`, use `AttributeRouteControllerLoader` instead
|
||||
* Deprecate `AddExpressionLanguageProvidersPass`, use `Symfony\Component\Routing\DependencyInjection\AddExpressionLanguageProvidersPass` instead
|
||||
* Deprecate `DataCollectorTranslatorPass`, use `Symfony\Component\Translation\DependencyInjection\DataCollectorTranslatorPass` instead
|
||||
* Deprecate `LoggingTranslatorPass`, use `Symfony\Component\Translation\DependencyInjection\LoggingTranslatorPass` instead
|
||||
* Deprecate `WorkflowGuardListenerPass`, use `Symfony\Component\Workflow\DependencyInjection\WorkflowGuardListenerPass` instead
|
||||
|
||||
6.3
|
||||
---
|
||||
|
||||
* Add `extra` option for `http_client.default_options` and `http_client.scoped_client`
|
||||
* Add `DomCrawlerAssertionsTrait::assertSelectorCount(int $count, string $selector)`
|
||||
* Allow to avoid `limit` definition in a RateLimiter configuration when using the `no_limit` policy
|
||||
* Add `--format` option to the `debug:config` command
|
||||
* Add support to pass namespace wildcard in `framework.messenger.routing`
|
||||
* Deprecate `framework:exceptions` tag, unwrap it and replace `framework:exception` tags' `name` attribute by `class`
|
||||
* Deprecate the `notifier.logger_notification_listener` service, use the `notifier.notification_logger_listener` service instead
|
||||
* Allow setting private services with the test container
|
||||
* Register alias for argument for workflow services with workflow name only
|
||||
* Configure the `ErrorHandler` on `FrameworkBundle::boot()`
|
||||
* Allow setting `debug.container.dump` to `false` to disable dumping the container to XML
|
||||
* Add `framework.http_cache.skip_response_headers` option
|
||||
* Display warmers duration on debug verbosity for `cache:clear` command
|
||||
* Add `AbstractController::sendEarlyHints()` to send HTTP Early Hints
|
||||
* Add autowiring aliases for `Http\Client\HttpAsyncClient`
|
||||
* Deprecate the `Http\Client\HttpClient` service, use `Psr\Http\Client\ClientInterface` instead
|
||||
* Add `stop_worker_on_signals` configuration option to `messenger` to define signals which would stop a worker
|
||||
* Add support for `--all` option to clear all cache pools with `cache:pool:clear` command
|
||||
* Add `--show-aliases` option to `debug:router` command
|
||||
|
||||
6.2
|
||||
---
|
||||
|
||||
* Add `resolve-env` option to `debug:config` command to display actual values of environment variables in dumped configuration
|
||||
* Add `NotificationAssertionsTrait`
|
||||
* Add option `framework.handle_all_throwables` to allow `Symfony\Component\HttpKernel\HttpKernel` to handle all kinds of `Throwable`
|
||||
* Make `AbstractController::render()` able to deal with forms and deprecate `renderForm()`
|
||||
* Deprecate the `Symfony\Component\Serializer\Normalizer\ObjectNormalizer` and
|
||||
`Symfony\Component\Serializer\Normalizer\PropertyNormalizer` autowiring aliases, type-hint against
|
||||
`Symfony\Component\Serializer\Normalizer\NormalizerInterface` or implement `NormalizerAwareInterface` instead
|
||||
* Add service usages list to the `debug:container` command output
|
||||
* Add service and alias deprecation message to `debug:container [<name>]` output
|
||||
* Tag all workflows services with `workflow`, those with type=workflow are
|
||||
tagged with `workflow.workflow`, and those with type=state_machine with
|
||||
`workflow.state_machine`
|
||||
* Add `rate_limiter` configuration option to `messenger.transport` to allow rate limited transports using the RateLimiter component
|
||||
* Remove `@internal` tag from secret vaults to allow them to be used directly outside the framework bundle and custom vaults to be added
|
||||
* Deprecate `framework.form.legacy_error_messages` config node
|
||||
* Add a `framework.router.cache_dir` configuration option to configure the default `Router` `cache_dir` option
|
||||
* Add option `framework.messenger.buses.*.default_middleware.allow_no_senders` to enable throwing when a message doesn't have a sender
|
||||
* Deprecate `AbstractController::renderForm()`, use `render()` instead
|
||||
* Deprecate `FrameworkExtension::registerRateLimiter()`
|
||||
|
||||
6.1
|
||||
---
|
||||
|
||||
* Add support for configuring semaphores
|
||||
* Environment variable `SYMFONY_IDE` is read by default when `framework.ide` config is not set
|
||||
* Load PHP configuration files by default in the `MicroKernelTrait`
|
||||
* Add `cache:pool:invalidate-tags` command
|
||||
* Add `xliff` support in addition to `xlf` for `XliffFileDumper`
|
||||
* Deprecate the `reset_on_message` config option. It can be set to `true` only and does nothing now
|
||||
* Add `trust_x_sendfile_type_header` option
|
||||
* Add support for first-class callable route controller in `MicroKernelTrait`
|
||||
* Add tag `routing.condition_service` to autoconfigure routing condition services
|
||||
* Automatically register kernel methods marked with the `Symfony\Component\Routing\Annotation\Route` attribute or annotation as controllers in `MicroKernelTrait`
|
||||
* Deprecate not setting the `http_method_override` config option. The default value will change to `false` in 7.0.
|
||||
* Add `framework.profiler.collect_serializer_data` config option, set it to `true` to enable the serializer data collector and profiler panel
|
||||
|
||||
6.0
|
||||
---
|
||||
|
||||
* Remove the `session.storage` alias and `session.storage.*` services, use the `session.storage.factory` alias and `session.storage.factory.*` services instead
|
||||
* Remove `framework.session.storage_id` configuration option, use the `framework.session.storage_factory_id` configuration option instead
|
||||
* Remove the `session` service and the `SessionInterface` alias, use the `\Symfony\Component\HttpFoundation\Request::getSession()` or the new `\Symfony\Component\HttpFoundation\RequestStack::getSession()` methods instead
|
||||
* Remove the `session.attribute_bag` service and `session.flash_bag` service
|
||||
* Remove the `lock.RESOURCE_NAME` and `lock.RESOURCE_NAME.store` services and the `lock`, `LockInterface`, `lock.store` and `PersistingStoreInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead
|
||||
* The `form.factory`, `form.type.file`, `translator`, `security.csrf.token_manager`, `serializer`,
|
||||
`cache_clearer`, `filesystem` and `validator` services are now private
|
||||
* Remove the `output-format` and `xliff-version` options from `TranslationUpdateCommand`
|
||||
* Remove `has()`, `get()`, `getDoctrine()`n and `dispatchMessage()` from `AbstractController`, use method/constructor injection instead
|
||||
* Make the "framework.router.utf8" configuration option default to `true`
|
||||
* Remove the `AdapterInterface` autowiring alias, use `CacheItemPoolInterface` instead
|
||||
* Make the `profiler` service private
|
||||
* Remove all other values than "none", "php_array" and "file" for `framework.annotation.cache`
|
||||
* Register workflow services as private
|
||||
* Remove support for passing a `RouteCollectionBuilder` to `MicroKernelTrait::configureRoutes()`, type-hint `RoutingConfigurator` instead
|
||||
* Remove the `cache.adapter.doctrine` service
|
||||
* Remove the `framework.translator.enabled_locales` config option, use `framework.enabled_locales` instead
|
||||
* Make the `framework.messenger.reset_on_message` configuration option default to `true`
|
||||
|
||||
5.4
|
||||
---
|
||||
|
||||
* Add `set_locale_from_accept_language` config option to automatically set the request locale based on the `Accept-Language`
|
||||
HTTP request header and the `framework.enabled_locales` config option
|
||||
* Add `set_content_language_from_locale` config option to automatically set the `Content-Language` HTTP response header based on the Request locale
|
||||
* Deprecate the `framework.translator.enabled_locales`, use `framework.enabled_locales` instead
|
||||
* Add autowiring alias for `HttpCache\StoreInterface`
|
||||
* Add the ability to enable the profiler using a request query parameter, body parameter or attribute
|
||||
* Deprecate the `AdapterInterface` autowiring alias, use `CacheItemPoolInterface` instead
|
||||
* Deprecate the public `profiler` service to private
|
||||
* Deprecate `get()`, `has()`, `getDoctrine()`, and `dispatchMessage()` in `AbstractController`, use method/constructor injection instead
|
||||
* Deprecate the `cache.adapter.doctrine` service
|
||||
* Add support for resetting container services after each messenger message
|
||||
* Add `configureContainer()`, `configureRoutes()`, `getConfigDir()` and `getBundlesPath()` to `MicroKernelTrait`
|
||||
* Add support for configuring log level, and status code by exception class
|
||||
* Bind the `default_context` parameter onto serializer's encoders and normalizers
|
||||
* Add support for `statusCode` default parameter when loading a template directly from route using the `Symfony\Bundle\FrameworkBundle\Controller\TemplateController` controller
|
||||
* Deprecate `translation:update` command, use `translation:extract` instead
|
||||
* Add `PhpStanExtractor` support for the PropertyInfo component
|
||||
* Add `cache.adapter.doctrine_dbal` service to replace `cache.adapter.pdo` when a Doctrine DBAL connection is used.
|
||||
|
||||
5.3
|
||||
---
|
||||
|
||||
* Deprecate the `session.storage` alias and `session.storage.*` services, use the `session.storage.factory` alias and `session.storage.factory.*` services instead
|
||||
* Deprecate the `framework.session.storage_id` configuration option, use the `framework.session.storage_factory_id` configuration option instead
|
||||
* Deprecate the `session` service and the `SessionInterface` alias, use the `Request::getSession()` or the new `RequestStack::getSession()` methods instead
|
||||
* Add `AbstractController::renderForm()` to render a form and set the appropriate HTTP status code
|
||||
* Add support for configuring PHP error level to log levels
|
||||
* Add the `dispatcher` option to `debug:event-dispatcher`
|
||||
* Add the `event_dispatcher.dispatcher` tag
|
||||
* Add `assertResponseFormatSame()` in `BrowserKitAssertionsTrait`
|
||||
* Add support for configuring UUID factory services
|
||||
* Add tag `assets.package` to register asset packages
|
||||
* Add support to use a PSR-6 compatible cache for Doctrine annotations
|
||||
* Deprecate all other values than "none", "php_array" and "file" for `framework.annotation.cache`
|
||||
* Add `KernelTestCase::getContainer()` as the best way to get a container in tests
|
||||
* Rename the container parameter `profiler_listener.only_master_requests` to `profiler_listener.only_main_requests`
|
||||
* Add service `fragment.uri_generator` to generate the URI of a fragment
|
||||
* Deprecate registering workflow services as public
|
||||
* Deprecate option `--xliff-version` of the `translation:update` command, use e.g. `--format=xlf20` instead
|
||||
* Deprecate option `--output-format` of the `translation:update` command, use e.g. `--format=xlf20` instead
|
||||
|
||||
5.2.0
|
||||
-----
|
||||
|
||||
* Added `framework.http_cache` configuration tree
|
||||
* Added `framework.trusted_proxies` and `framework.trusted_headers` configuration options
|
||||
* Deprecated the public `form.factory`, `form.type.file`, `translator`, `security.csrf.token_manager`, `serializer`,
|
||||
`cache_clearer`, `filesystem` and `validator` services to private.
|
||||
* Added `TemplateAwareDataCollectorInterface` and `AbstractDataCollector` to simplify custom data collector creation and leverage autoconfiguration
|
||||
* Add `cache.adapter.redis_tag_aware` tag to use `RedisCacheAwareAdapter`
|
||||
* added `framework.http_client.retry_failing` configuration tree
|
||||
* added `assertCheckboxChecked()` and `assertCheckboxNotChecked()` in `WebTestCase`
|
||||
* added `assertFormValue()` and `assertNoFormValue()` in `WebTestCase`
|
||||
* Added "--as-tree=3" option to `translation:update` command to dump messages as a tree-like structure. The given value defines the level where to switch to inline YAML
|
||||
* Deprecated the `lock.RESOURCE_NAME` and `lock.RESOURCE_NAME.store` services and the `lock`, `LockInterface`, `lock.store` and `PersistingStoreInterface` aliases, use `lock.RESOURCE_NAME.factory`, `lock.factory` or `LockFactory` instead.
|
||||
|
||||
5.1.0
|
||||
-----
|
||||
* Removed `--no-backup` option from `translation:update` command (broken since `5.0.0`)
|
||||
* Added link to source for controllers registered as named services
|
||||
* Added link to source on controller on `router:match`/`debug:router` (when `framework.ide` is configured)
|
||||
* Added the `framework.router.default_uri` configuration option to configure the default `RequestContext`
|
||||
* Made `MicroKernelTrait::configureContainer()` compatible with `ContainerConfigurator`
|
||||
* Added a new `mailer.message_bus` option to configure or disable the message bus to use to send mails.
|
||||
* Added flex-compatible default implementation for `MicroKernelTrait::registerBundles()`
|
||||
* Deprecated passing a `RouteCollectionBuilder` to `MicroKernelTrait::configureRoutes()`, type-hint `RoutingConfigurator` instead
|
||||
* The `TemplateController` now accepts context argument
|
||||
* Deprecated *not* setting the "framework.router.utf8" configuration option as it will default to `true` in Symfony 6.0
|
||||
* Added tag `routing.expression_language_function` to define functions available in route conditions
|
||||
* Added `debug:container --deprecations` option to see compile-time deprecations.
|
||||
* Made `BrowserKitAssertionsTrait` report the original error message in case of a failure
|
||||
* Added ability for `config:dump-reference` and `debug:config` to dump and debug kernel container extension configuration.
|
||||
* Deprecated `session.attribute_bag` service and `session.flash_bag` service.
|
||||
|
||||
5.0.0
|
||||
-----
|
||||
|
||||
* Removed support to load translation resources from the legacy directories `src/Resources/translations/` and `src/Resources/<BundleName>/translations/`
|
||||
* Removed `ControllerNameParser`.
|
||||
* Removed `ResolveControllerNameSubscriber`
|
||||
* Removed support for `bundle:controller:action` to reference controllers. Use `serviceOrFqcn::method` instead
|
||||
* Removed support for PHP templating, use Twig instead
|
||||
* Removed `Controller`, use `AbstractController` instead
|
||||
* Removed `Client`, use `KernelBrowser` instead
|
||||
* Removed `ContainerAwareCommand`, use dependency injection instead
|
||||
* Removed the `validation.strict_email` option, use `validation.email_validation_mode` instead
|
||||
* Removed the `cache.app.simple` service and its corresponding PSR-16 autowiring alias
|
||||
* Removed cache-related compiler passes and `RequestDataCollector`
|
||||
* Removed the `translator.selector` and `session.save_listener` services
|
||||
* Removed `SecurityUserValueResolver`, use `UserValueResolver` instead
|
||||
* Removed `routing.loader.service`.
|
||||
* Service route loaders must be tagged with `routing.route_loader`.
|
||||
* Added `slugger` service and `SluggerInterface` alias
|
||||
* Removed the `lock.store.flock`, `lock.store.semaphore`, `lock.store.memcached.abstract` and `lock.store.redis.abstract` services.
|
||||
* Removed the `router.cache_class_prefix` parameter.
|
||||
|
||||
4.4.0
|
||||
-----
|
||||
|
||||
* Added `lint:container` command to check that services wiring matches type declarations
|
||||
* Added `MailerAssertionsTrait`
|
||||
* Deprecated support for `templating` engine in `TemplateController`, use Twig instead
|
||||
* Deprecated the `$parser` argument of `ControllerResolver::__construct()` and `DelegatingLoader::__construct()`
|
||||
* Deprecated the `controller_name_converter` and `resolve_controller_name_subscriber` services
|
||||
* The `ControllerResolver` and `DelegatingLoader` classes have been marked as `final`
|
||||
* Added support for configuring chained cache pools
|
||||
* Deprecated calling `WebTestCase::createClient()` while a kernel has been booted, ensure the kernel is shut down before calling the method
|
||||
* Deprecated `routing.loader.service`, use `routing.loader.container` instead.
|
||||
* Not tagging service route loaders with `routing.route_loader` has been deprecated.
|
||||
* Overriding the methods `KernelTestCase::tearDown()` and `WebTestCase::tearDown()` without the `void` return-type is deprecated.
|
||||
* Added new `error_controller` configuration to handle system exceptions
|
||||
* Added sort option for `translation:update` command.
|
||||
* [BC Break] The `framework.messenger.routing.senders` config key is not deeply merged anymore.
|
||||
* Added `secrets:*` commands to deal with secrets seamlessly.
|
||||
* Made `framework.session.handler_id` accept a DSN
|
||||
* Marked the `RouterDataCollector` class as `@final`.
|
||||
* [BC Break] The `framework.messenger.buses.<name>.middleware` config key is not deeply merged anymore.
|
||||
* Moved `MailerAssertionsTrait` in `KernelTestCase`
|
||||
|
||||
4.3.0
|
||||
-----
|
||||
|
||||
* Deprecated the `framework.templating` option, configure the Twig bundle instead.
|
||||
* Added `WebTestAssertionsTrait` (included by default in `WebTestCase`)
|
||||
* Renamed `Client` to `KernelBrowser`
|
||||
* Not passing the project directory to the constructor of the `AssetsInstallCommand` is deprecated. This argument will
|
||||
be mandatory in 5.0.
|
||||
* Deprecated the "Psr\SimpleCache\CacheInterface" / "cache.app.simple" service, use "Symfony\Contracts\Cache\CacheInterface" / "cache.app" instead
|
||||
* Added the ability to specify a custom `serializer` option for each
|
||||
transport under`framework.messenger.transports`.
|
||||
* Added the `RegisterLocaleAwareServicesPass` and configured the `LocaleAwareListener`
|
||||
* [BC Break] When using Messenger, the default transport changed from
|
||||
using Symfony's serializer service to use `PhpSerializer`, which uses
|
||||
PHP's native `serialize()` and `unserialize()` functions. To use the
|
||||
original serialization method, set the `framework.messenger.default_serializer`
|
||||
config option to `messenger.transport.symfony_serializer`. Or set the
|
||||
`serializer` option under one specific `transport`.
|
||||
* [BC Break] The `framework.messenger.serializer` config key changed to
|
||||
`framework.messenger.default_serializer`, which holds the string service
|
||||
id and `framework.messenger.symfony_serializer`, which configures the
|
||||
options if you're using Symfony's serializer.
|
||||
* [BC Break] Removed the `framework.messenger.routing.send_and_handle` configuration.
|
||||
Instead of setting it to true, configure a `SyncTransport` and route messages to it.
|
||||
* Added information about deprecated aliases in `debug:autowiring`
|
||||
* Added php ini session options `sid_length` and `sid_bits_per_character`
|
||||
to the `session` section of the configuration
|
||||
* Added support for Translator paths, Twig paths in translation commands.
|
||||
* Added support for PHP files with translations in translation commands.
|
||||
* Added support for boolean container parameters within routes.
|
||||
* Added the `messenger:setup-transports` command to setup messenger transports
|
||||
* Added a `InMemoryTransport` to Messenger. Use it with a DSN starting with `in-memory://`.
|
||||
* Added `framework.property_access.throw_exception_on_invalid_property_path` config option.
|
||||
* Added `cache:pool:list` command to list all available cache pools.
|
||||
|
||||
4.2.0
|
||||
-----
|
||||
|
||||
* Added a `AbstractController::addLink()` method to add Link headers to the current response
|
||||
* Allowed configuring taggable cache pools via a new `framework.cache.pools.tags` option (bool|service-id)
|
||||
* Allowed configuring PDO-based cache pools via a new `cache.adapter.pdo` abstract service
|
||||
* Deprecated auto-injection of the container in AbstractController instances, register them as service subscribers instead
|
||||
* Deprecated processing of services tagged `security.expression_language_provider` in favor of a new `AddExpressionLanguageProvidersPass` in SecurityBundle.
|
||||
* Deprecated the `Symfony\Bundle\FrameworkBundle\Controller\Controller` class in favor of `Symfony\Bundle\FrameworkBundle\Controller\AbstractController`.
|
||||
* Enabled autoconfiguration for `Psr\Log\LoggerAwareInterface`
|
||||
* Added new "auto" mode for `framework.session.cookie_secure` to turn it on when HTTPS is used
|
||||
* Removed the `framework.messenger.encoder` and `framework.messenger.decoder` options. Use the `framework.messenger.serializer.id` option to replace the Messenger serializer.
|
||||
* Deprecated the `ContainerAwareCommand` class in favor of `Symfony\Component\Console\Command\Command`
|
||||
* Made `debug:container` and `debug:autowiring` ignore backslashes in service ids
|
||||
* Deprecated the `Templating\Helper\TranslatorHelper::transChoice()` method, use the `trans()` one instead with a `%count%` parameter
|
||||
* Deprecated `CacheCollectorPass`. Use `Symfony\Component\Cache\DependencyInjection\CacheCollectorPass` instead.
|
||||
* Deprecated `CachePoolClearerPass`. Use `Symfony\Component\Cache\DependencyInjection\CachePoolClearerPass` instead.
|
||||
* Deprecated `CachePoolPass`. Use `Symfony\Component\Cache\DependencyInjection\CachePoolPass` instead.
|
||||
* Deprecated `CachePoolPrunerPass`. Use `Symfony\Component\Cache\DependencyInjection\CachePoolPrunerPass` instead.
|
||||
* Deprecated support for legacy translations directories `src/Resources/translations/` and `src/Resources/<BundleName>/translations/`, use `translations/` instead.
|
||||
* Deprecated support for the legacy directory structure in `translation:update` and `debug:translation` commands.
|
||||
|
||||
4.1.0
|
||||
-----
|
||||
|
||||
* Allowed to pass an optional `LoggerInterface $logger` instance to the `Router`
|
||||
* Added a new `parameter_bag` service with related autowiring aliases to access parameters as-a-service
|
||||
* Allowed the `Router` to work with any PSR-11 container
|
||||
* Added option in workflow dump command to label graph with a custom label
|
||||
* Using a `RouterInterface` that does not implement the `WarmableInterface` is deprecated.
|
||||
* Warming up a router in `RouterCacheWarmer` that does not implement the `WarmableInterface` is deprecated and will not
|
||||
be supported anymore in 5.0.
|
||||
* The `RequestDataCollector` class has been deprecated. Use the `Symfony\Component\HttpKernel\DataCollector\RequestDataCollector` class instead.
|
||||
* The `RedirectController` class allows for 307/308 HTTP status codes
|
||||
* Deprecated `bundle:controller:action` syntax to reference controllers. Use `serviceOrFqcn::method` instead where `serviceOrFqcn`
|
||||
is either the service ID or the FQCN of the controller.
|
||||
* Deprecated `Symfony\Bundle\FrameworkBundle\Controller\ControllerNameParser`
|
||||
* The `container.service_locator` tag of `ServiceLocator`s is now autoconfigured.
|
||||
* Add the ability to search a route in `debug:router`.
|
||||
* Add the ability to use SameSite cookies for sessions.
|
||||
|
||||
4.0.0
|
||||
-----
|
||||
|
||||
* The default `type` option of the `framework.workflows.*` configuration entries is `state_machine`
|
||||
* removed `AddConsoleCommandPass`, `AddConstraintValidatorsPass`,
|
||||
`AddValidatorInitializersPass`, `CompilerDebugDumpPass`, `ConfigCachePass`,
|
||||
`ControllerArgumentValueResolverPass`, `FormPass`, `PropertyInfoPass`,
|
||||
`RoutingResolverPass`, `SerializerPass`, `ValidateWorkflowsPass`
|
||||
* made `Translator::__construct()` `$defaultLocale` argument required
|
||||
* removed `SessionListener`, `TestSessionListener`
|
||||
* Removed `cache:clear` warmup part along with the `--no-optional-warmers` option
|
||||
* Removed core form types services registration when unnecessary
|
||||
* Removed `framework.serializer.cache` option and `serializer.mapping.cache.apc`, `serializer.mapping.cache.doctrine.apc` services
|
||||
* Removed `ConstraintValidatorFactory`
|
||||
* Removed class parameters related to routing
|
||||
* Removed absolute template paths support in the template name parser
|
||||
* Removed support of the `KERNEL_DIR` environment variable with `KernelTestCase::getKernelClass()`.
|
||||
* Removed the `KernelTestCase::getPhpUnitXmlDir()` and `KernelTestCase::getPhpUnitCliConfigArgument()` methods.
|
||||
* Removed the "framework.validation.cache" configuration option. Configure the "cache.validator" service under "framework.cache.pools" instead.
|
||||
* Removed `PhpStringTokenParser`, use `Symfony\Component\Translation\Extractor\PhpStringTokenParser` instead.
|
||||
* Removed `PhpExtractor`, use `Symfony\Component\Translation\Extractor\PhpExtractor` instead.
|
||||
* Removed the `use_strict_mode` session option, it's is now enabled by default
|
||||
|
||||
3.4.0
|
||||
-----
|
||||
|
||||
* Added `translator.default_path` option and parameter
|
||||
* Session `use_strict_mode` is now enabled by default and the corresponding option has been deprecated
|
||||
* Made the `cache:clear` command to *not* clear "app" PSR-6 cache pools anymore,
|
||||
but to still clear "system" ones; use the `cache:pool:clear` command to clear "app" pools instead
|
||||
* Always register a minimalist logger that writes in `stderr`
|
||||
* Deprecated `profiler.matcher` option
|
||||
* Added support for `EventSubscriberInterface` on `MicroKernelTrait`
|
||||
* Removed `doctrine/cache` from the list of required dependencies in `composer.json`
|
||||
* Deprecated `validator.mapping.cache.doctrine.apc` service
|
||||
* The `symfony/stopwatch` dependency has been removed, require it via `composer
|
||||
require symfony/stopwatch` in your `dev` environment.
|
||||
* Deprecated using the `KERNEL_DIR` environment variable with `KernelTestCase::getKernelClass()`.
|
||||
* Deprecated the `KernelTestCase::getPhpUnitXmlDir()` and `KernelTestCase::getPhpUnitCliConfigArgument()` methods.
|
||||
* Deprecated `AddCacheClearerPass`, use tagged iterator arguments instead.
|
||||
* Deprecated `AddCacheWarmerPass`, use tagged iterator arguments instead.
|
||||
* Deprecated `TranslationDumperPass`, use
|
||||
`Symfony\Component\Translation\DependencyInjection\TranslationDumperPass` instead
|
||||
* Deprecated `TranslationExtractorPass`, use
|
||||
`Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass` instead
|
||||
* Deprecated `TranslatorPass`, use
|
||||
`Symfony\Component\Translation\DependencyInjection\TranslatorPass` instead
|
||||
* Added `command` attribute to the `console.command` tag which takes the command
|
||||
name as value, using it makes the command lazy
|
||||
* Added `cache:pool:prune` command to allow manual stale cache item pruning of supported PSR-6 and PSR-16 cache pool
|
||||
implementations
|
||||
* Deprecated `Symfony\Bundle\FrameworkBundle\Translation\TranslationLoader`, use
|
||||
`Symfony\Component\Translation\Reader\TranslationReader` instead
|
||||
* Deprecated `translation.loader` service, use `translation.reader` instead
|
||||
* `AssetsInstallCommand::__construct()` now takes an instance of
|
||||
`Symfony\Component\Filesystem\Filesystem` as first argument
|
||||
* `CacheClearCommand::__construct()` now takes an instance of
|
||||
`Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface` as
|
||||
first argument
|
||||
* `CachePoolClearCommand::__construct()` now takes an instance of
|
||||
`Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer` as
|
||||
first argument
|
||||
* `EventDispatcherDebugCommand::__construct()` now takes an instance of
|
||||
`Symfony\Component\EventDispatcher\EventDispatcherInterface` as
|
||||
first argument
|
||||
* `RouterDebugCommand::__construct()` now takes an instance of
|
||||
`Symfony\Component\Routing\RouterInterface` as
|
||||
first argument
|
||||
* `RouterMatchCommand::__construct()` now takes an instance of
|
||||
`Symfony\Component\Routing\RouterInterface` as
|
||||
first argument
|
||||
* `TranslationDebugCommand::__construct()` now takes an instance of
|
||||
`Symfony\Component\Translation\TranslatorInterface` as
|
||||
first argument
|
||||
* `TranslationUpdateCommand::__construct()` now takes an instance of
|
||||
`Symfony\Component\Translation\TranslatorInterface` as
|
||||
first argument
|
||||
* `AssetsInstallCommand`, `CacheClearCommand`, `CachePoolClearCommand`,
|
||||
`EventDispatcherDebugCommand`, `RouterDebugCommand`, `RouterMatchCommand`,
|
||||
`TranslationDebugCommand`, `TranslationUpdateCommand`, `XliffLintCommand`
|
||||
and `YamlLintCommand` classes have been marked as final
|
||||
* Added `asset.request_context.base_path` and `asset.request_context.secure` parameters
|
||||
to provide a default request context in case the stack is empty (similar to `router.request_context.*` parameters)
|
||||
* Display environment variables managed by `Dotenv` in `AboutCommand`
|
||||
|
||||
3.3.0
|
||||
-----
|
||||
|
||||
* Not defining the `type` option of the `framework.workflows.*` configuration entries is deprecated.
|
||||
The default value will be `state_machine` in Symfony 4.0.
|
||||
* Deprecated the `CompilerDebugDumpPass` class
|
||||
* Deprecated the "framework.trusted_proxies" configuration option and the corresponding "kernel.trusted_proxies" parameter
|
||||
* Added a new version strategy option called "json_manifest_path"
|
||||
that allows you to use the `JsonManifestVersionStrategy`.
|
||||
* Added `Symfony\Bundle\FrameworkBundle\Controller\AbstractController`. It provides
|
||||
the same helpers as the `Controller` class, but does not allow accessing the dependency
|
||||
injection container, in order to encourage explicit dependency declarations.
|
||||
* Added support for the `controller.service_arguments` tag, for injecting services into controllers' actions
|
||||
* Changed default configuration for
|
||||
assets/forms/validation/translation/serialization/csrf from `canBeEnabled()` to
|
||||
`canBeDisabled()` when Flex is used
|
||||
* The server:* commands and their associated router files were moved to WebServerBundle
|
||||
* Translation related services are not loaded anymore when the `framework.translator` option
|
||||
is disabled.
|
||||
* Added `GlobalVariables::getToken()`
|
||||
* Deprecated `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass`. Use `Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass` instead.
|
||||
* Added configurable paths for validation files
|
||||
* Deprecated `SerializerPass`, use `Symfony\Component\Serializer\DependencyInjection\SerializerPass` instead
|
||||
* Deprecated `FormPass`, use `Symfony\Component\Form\DependencyInjection\FormPass` instead
|
||||
* Deprecated `SessionListener`
|
||||
* Deprecated `TestSessionListener`
|
||||
* Deprecated `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ConfigCachePass`.
|
||||
Use tagged iterator arguments instead.
|
||||
* Deprecated `PropertyInfoPass`, use `Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass` instead
|
||||
* Deprecated `ControllerArgumentValueResolverPass`. Use
|
||||
`Symfony\Component\HttpKernel\DependencyInjection\ControllerArgumentValueResolverPass` instead
|
||||
* Deprecated `RoutingResolverPass`, use `Symfony\Component\Routing\DependencyInjection\RoutingResolverPass` instead
|
||||
* [BC BREAK] The `server:run`, `server:start`, `server:stop` and
|
||||
`server:status` console commands have been moved to a dedicated bundle.
|
||||
Require `symfony/web-server-bundle` in your composer.json and register
|
||||
`Symfony\Bundle\WebServerBundle\WebServerBundle` in your AppKernel to use them.
|
||||
* Added `$defaultLocale` as 3rd argument of `Translator::__construct()`
|
||||
making `Translator` works with any PSR-11 container
|
||||
* Added `framework.serializer.mapping` config option allowing to define custom
|
||||
serialization mapping files and directories
|
||||
* Deprecated `AddValidatorInitializersPass`, use
|
||||
`Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass` instead
|
||||
* Deprecated `AddConstraintValidatorsPass`, use
|
||||
`Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass` instead
|
||||
* Deprecated `ValidateWorkflowsPass`, use
|
||||
`Symfony\Component\Workflow\DependencyInjection\ValidateWorkflowsPass` instead
|
||||
* Deprecated `ConstraintValidatorFactory`, use
|
||||
`Symfony\Component\Validator\ContainerConstraintValidatorFactory` instead.
|
||||
* Deprecated `PhpStringTokenParser`, use
|
||||
`Symfony\Component\Translation\Extractor\PhpStringTokenParser` instead.
|
||||
* Deprecated `PhpExtractor`, use
|
||||
`Symfony\Component\Translation\Extractor\PhpExtractor` instead.
|
||||
|
||||
3.2.0
|
||||
-----
|
||||
|
||||
* Removed `doctrine/annotations` from the list of required dependencies in `composer.json`
|
||||
* Removed `symfony/security-core` and `symfony/security-csrf` from the list of required dependencies in `composer.json`
|
||||
* Removed `symfony/templating` from the list of required dependencies in `composer.json`
|
||||
* Removed `symfony/translation` from the list of required dependencies in `composer.json`
|
||||
* Removed `symfony/asset` from the list of required dependencies in `composer.json`
|
||||
* The `Resources/public/images/*` files have been removed.
|
||||
* The `Resources/public/css/*.css` files have been removed (they are now inlined in TwigBundle).
|
||||
* Added possibility to prioritize form type extensions with `'priority'` attribute on tags `form.type_extension`
|
||||
|
||||
3.1.0
|
||||
-----
|
||||
|
||||
* Added `Controller::json` to simplify creating JSON responses when using the Serializer component
|
||||
* Deprecated absolute template paths support in the template name parser
|
||||
* Deprecated using core form types without dependencies as services
|
||||
* Added `Symfony\Component\HttpHernel\DataCollector\RequestDataCollector::onKernelResponse()`
|
||||
* Added `Symfony\Bundle\FrameworkBundle\DataCollector\RequestDataCollector`
|
||||
* The `framework.serializer.cache` option and the service `serializer.mapping.cache.apc` have been
|
||||
deprecated. APCu should now be automatically used when available.
|
||||
|
||||
3.0.0
|
||||
-----
|
||||
|
||||
* removed `validator.api` parameter
|
||||
* removed `alias` option of the `form.type` tag
|
||||
|
||||
2.8.0
|
||||
-----
|
||||
|
||||
* Deprecated the `alias` option of the `form.type_extension` tag in favor of the
|
||||
`extended_type`/`extended-type` option
|
||||
* Deprecated the `alias` option of the `form.type` tag
|
||||
* Deprecated the Shell
|
||||
|
||||
2.7.0
|
||||
-----
|
||||
|
||||
* Added possibility to extract translation messages from a file or files besides extracting from a directory
|
||||
* Added `TranslationsCacheWarmer` to create catalogues at warmup
|
||||
|
||||
2.6.0
|
||||
-----
|
||||
|
||||
* Added helper commands (`server:start`, `server:stop` and `server:status`) to control the built-in web
|
||||
server in the background
|
||||
* Added `Controller::isCsrfTokenValid` helper
|
||||
* Added configuration for the PropertyAccess component
|
||||
* Added `Controller::redirectToRoute` helper
|
||||
* Added `Controller::addFlash` helper
|
||||
* Added `Controller::isGranted` helper
|
||||
* Added `Controller::denyAccessUnlessGranted` helper
|
||||
* Deprecated `app.security` in twig as `app.user` and `is_granted()` are already available
|
||||
|
||||
2.5.0
|
||||
-----
|
||||
|
||||
* Added `translation:debug` command
|
||||
* Added `--no-backup` option to `translation:update` command
|
||||
* Added `config:debug` command
|
||||
* Added `yaml:lint` command
|
||||
* Deprecated the `RouterApacheDumperCommand` which will be removed in Symfony 3.0.
|
||||
|
||||
2.4.0
|
||||
-----
|
||||
|
||||
* allowed multiple IP addresses in profiler matcher settings
|
||||
* added stopwatch helper to time templates with the WebProfilerBundle
|
||||
* added service definition for "security.secure_random" service
|
||||
* added service definitions for the new Security CSRF sub-component
|
||||
|
||||
2.3.0
|
||||
-----
|
||||
|
||||
* [BC BREAK] added a way to disable the profiler (when disabling the profiler, it is now completely removed)
|
||||
To get the same "disabled" behavior as before, set `enabled` to `true` and `collect` to `false`
|
||||
* [BC BREAK] the `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RegisterKernelListenersPass` was moved
|
||||
to `Component\HttpKernel\DependencyInjection\RegisterListenersPass`
|
||||
* added ControllerNameParser::build() which converts a controller short notation (a:b:c) to a class::method notation
|
||||
* added possibility to run PHP built-in server in production environment
|
||||
* added possibility to load the serializer component in the service container
|
||||
* added route debug information when using the `router:match` command
|
||||
* added `TimedPhpEngine`
|
||||
* added `--clean` option to the `translation:update` command
|
||||
* added `http_method_override` option
|
||||
* added support for default templates per render tag
|
||||
* added FormHelper::form(), FormHelper::start() and FormHelper::end()
|
||||
* deprecated FormHelper::enctype() in favor of FormHelper::start()
|
||||
* RedirectController actions now receive the Request instance via the method signature.
|
||||
|
||||
2.2.0
|
||||
-----
|
||||
|
||||
* added a new `uri_signer` service to help sign URIs
|
||||
* deprecated `Symfony\Bundle\FrameworkBundle\HttpKernel::render()` and `Symfony\Bundle\FrameworkBundle\HttpKernel::forward()`
|
||||
* deprecated the `Symfony\Bundle\FrameworkBundle\HttpKernel` class in favor of `Symfony\Component\HttpKernel\DependencyInjection\ContainerAwareHttpKernel`
|
||||
* added support for adding new HTTP content rendering strategies (like ESI and Hinclude)
|
||||
in the DIC via the `kernel.fragment_renderer` tag
|
||||
* [BC BREAK] restricted the `Symfony\Bundle\FrameworkBundle\HttpKernel::render()` method to only accept URIs or ControllerReference instances
|
||||
* `Symfony\Bundle\FrameworkBundle\HttpKernel::render()` method signature changed and the first argument
|
||||
must now be a URI or a ControllerReference instance (the `generateInternalUri()` method was removed)
|
||||
* The internal routes (`Resources/config/routing/internal.xml`) have been removed and replaced with a listener (`Symfony\Component\HttpKernel\EventListener\FragmentListener`)
|
||||
* The `render` method of the `actions` templating helper signature and arguments changed
|
||||
* replaced Symfony\Bundle\FrameworkBundle\Controller\TraceableControllerResolver by Symfony\Component\HttpKernel\Controller\TraceableControllerResolver
|
||||
* replaced Symfony\Component\HttpKernel\Debug\ContainerAwareTraceableEventDispatcher by Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher
|
||||
* added Client::enableProfiler()
|
||||
* a new parameter has been added to the DIC: `router.request_context.base_url`
|
||||
You can customize it for your functional tests or for generating URLs with
|
||||
the right base URL when your are in the CLI context.
|
||||
* added support for default templates per render tag
|
||||
|
||||
2.1.0
|
||||
-----
|
||||
|
||||
* moved the translation files to the Form and Validator components
|
||||
* changed the default extension for XLIFF files from .xliff to .xlf
|
||||
* moved Symfony\Bundle\FrameworkBundle\ContainerAwareEventDispatcher to Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher
|
||||
* moved Symfony\Bundle\FrameworkBundle\Debug\TraceableEventDispatcher to Symfony\Component\EventDispatcher\ContainerAwareTraceableEventDispatcher
|
||||
* added a router:match command
|
||||
* added a config:dump-reference command
|
||||
* added a server:run command
|
||||
* added kernel.event_subscriber tag
|
||||
* added a way to create relative symlinks when running assets:install command (--relative option)
|
||||
* added Controller::getUser()
|
||||
* [BC BREAK] assets_base_urls and base_urls merging strategy has changed
|
||||
* changed the default profiler storage to use the filesystem instead of SQLite
|
||||
* added support for placeholders in route defaults and requirements (replaced
|
||||
by the value set in the service container)
|
||||
* added Filesystem component as a dependency
|
||||
* added support for hinclude (use ``standalone: 'js'`` in render tag)
|
||||
* session options: lifetime, path, domain, secure, httponly were deprecated.
|
||||
Prefixed versions should now be used instead: cookie_lifetime, cookie_path,
|
||||
cookie_domain, cookie_secure, cookie_httponly
|
||||
* [BC BREAK] following session options: 'lifetime', 'path', 'domain', 'secure',
|
||||
'httponly' are now prefixed with cookie_ when dumped to the container
|
||||
* Added `handler_id` configuration under `session` key to represent `session.handler`
|
||||
service, defaults to `session.handler.native_file`.
|
||||
* Added `gc_maxlifetime`, `gc_probability`, and `gc_divisor` to session
|
||||
configuration. This means session garbage collection has a
|
||||
`gc_probability`/`gc_divisor` chance of being run. The `gc_maxlifetime` defines
|
||||
how long a session can idle for. It is different from cookie lifetime which
|
||||
declares how long a cookie can be stored on the remote client.
|
||||
* Removed 'auto_start' configuration parameter from session config. The session will
|
||||
start on demand.
|
||||
* [BC BREAK] TemplateNameParser::parseFromFilename() has been moved to a dedicated
|
||||
parser: TemplateFilenameParser::parse().
|
||||
* [BC BREAK] Kernel parameters are replaced by their value wherever they appear
|
||||
in Route patterns, requirements and defaults. Use '%%' as the escaped value for '%'.
|
||||
* [BC BREAK] Switched behavior of flash messages to expire flash messages on retrieval
|
||||
using Symfony\Component\HttpFoundation\Session\Flash\FlashBag as opposed to on
|
||||
next pageload regardless of whether they are displayed or not.
|
||||
79
vendor/symfony/framework-bundle/CacheWarmer/AbstractPhpFileCacheWarmer.php
vendored
Normal file
79
vendor/symfony/framework-bundle/CacheWarmer/AbstractPhpFileCacheWarmer.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?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\Bundle\FrameworkBundle\CacheWarmer;
|
||||
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\NullAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
|
||||
use Symfony\Component\Config\Resource\ClassExistenceResource;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
|
||||
abstract class AbstractPhpFileCacheWarmer implements CacheWarmerInterface
|
||||
{
|
||||
/**
|
||||
* @param string $phpArrayFile The PHP file where metadata are cached
|
||||
*/
|
||||
public function __construct(
|
||||
private string $phpArrayFile,
|
||||
) {
|
||||
}
|
||||
|
||||
public function isOptional(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function warmUp(string $cacheDir, ?string $buildDir = null): array
|
||||
{
|
||||
$arrayAdapter = new ArrayAdapter();
|
||||
|
||||
spl_autoload_register([ClassExistenceResource::class, 'throwOnRequiredClass']);
|
||||
try {
|
||||
if (!$this->doWarmUp($cacheDir, $arrayAdapter, $buildDir)) {
|
||||
return [];
|
||||
}
|
||||
} finally {
|
||||
spl_autoload_unregister([ClassExistenceResource::class, 'throwOnRequiredClass']);
|
||||
}
|
||||
|
||||
// the ArrayAdapter stores the values serialized
|
||||
// to avoid mutation of the data after it was written to the cache
|
||||
// so here we un-serialize the values first
|
||||
$values = array_map(fn ($val) => null !== $val ? unserialize($val) : null, $arrayAdapter->getValues());
|
||||
|
||||
return $this->warmUpPhpArrayAdapter(new PhpArrayAdapter($this->phpArrayFile, new NullAdapter()), $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] A list of classes to preload on PHP 7.4+
|
||||
*/
|
||||
protected function warmUpPhpArrayAdapter(PhpArrayAdapter $phpArrayAdapter, array $values): array
|
||||
{
|
||||
return $phpArrayAdapter->warmUp($values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final protected function ignoreAutoloadException(string $class, \Exception $exception): void
|
||||
{
|
||||
try {
|
||||
ClassExistenceResource::throwOnRequiredClass($class, $exception);
|
||||
} catch (\ReflectionException) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool false if there is nothing to warm-up
|
||||
*/
|
||||
abstract protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter, ?string $buildDir = null): bool;
|
||||
}
|
||||
53
vendor/symfony/framework-bundle/CacheWarmer/CachePoolClearerCacheWarmer.php
vendored
Normal file
53
vendor/symfony/framework-bundle/CacheWarmer/CachePoolClearerCacheWarmer.php
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
<?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\Bundle\FrameworkBundle\CacheWarmer;
|
||||
|
||||
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
|
||||
/**
|
||||
* Clears the cache pools when warming up the cache.
|
||||
*
|
||||
* Do not use in production!
|
||||
*
|
||||
* @author Teoh Han Hui <teohhanhui@gmail.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class CachePoolClearerCacheWarmer implements CacheWarmerInterface
|
||||
{
|
||||
/**
|
||||
* @param string[] $pools
|
||||
*/
|
||||
public function __construct(
|
||||
private Psr6CacheClearer $poolClearer,
|
||||
private array $pools = [],
|
||||
) {
|
||||
}
|
||||
|
||||
public function warmUp(string $cacheDir, ?string $buildDir = null): array
|
||||
{
|
||||
foreach ($this->pools as $pool) {
|
||||
if ($this->poolClearer->hasPool($pool)) {
|
||||
$this->poolClearer->clearPool($pool);
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function isOptional(): bool
|
||||
{
|
||||
// optional cache warmers are not run when handling the request
|
||||
return false;
|
||||
}
|
||||
}
|
||||
104
vendor/symfony/framework-bundle/CacheWarmer/ConfigBuilderCacheWarmer.php
vendored
Normal file
104
vendor/symfony/framework-bundle/CacheWarmer/ConfigBuilderCacheWarmer.php
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
<?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\Bundle\FrameworkBundle\CacheWarmer;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Config\Builder\ConfigBuilderGenerator;
|
||||
use Symfony\Component\Config\Builder\ConfigBuilderGeneratorInterface;
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBag;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* Generate all config builders.
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*
|
||||
* @final since Symfony 7.1
|
||||
*/
|
||||
class ConfigBuilderCacheWarmer implements CacheWarmerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private KernelInterface $kernel,
|
||||
private ?LoggerInterface $logger = null,
|
||||
) {
|
||||
}
|
||||
|
||||
public function warmUp(string $cacheDir, ?string $buildDir = null): array
|
||||
{
|
||||
if (!$buildDir) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$generator = new ConfigBuilderGenerator($buildDir);
|
||||
|
||||
if ($this->kernel instanceof Kernel) {
|
||||
/** @var ContainerBuilder $container */
|
||||
$container = \Closure::bind(function (Kernel $kernel) {
|
||||
$containerBuilder = $kernel->getContainerBuilder();
|
||||
$kernel->prepareContainer($containerBuilder);
|
||||
|
||||
return $containerBuilder;
|
||||
}, null, $this->kernel)($this->kernel);
|
||||
|
||||
$extensions = $container->getExtensions();
|
||||
} else {
|
||||
$extensions = [];
|
||||
foreach ($this->kernel->getBundles() as $bundle) {
|
||||
$extension = $bundle->getContainerExtension();
|
||||
if (null !== $extension) {
|
||||
$extensions[] = $extension;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($extensions as $extension) {
|
||||
try {
|
||||
$this->dumpExtension($extension, $generator);
|
||||
} catch (\Exception $e) {
|
||||
$this->logger?->warning('Failed to generate ConfigBuilder for extension {extensionClass}: '.$e->getMessage(), ['exception' => $e, 'extensionClass' => $extension::class]);
|
||||
}
|
||||
}
|
||||
|
||||
// No need to preload anything
|
||||
return [];
|
||||
}
|
||||
|
||||
private function dumpExtension(ExtensionInterface $extension, ConfigBuilderGeneratorInterface $generator): void
|
||||
{
|
||||
$configuration = null;
|
||||
if ($extension instanceof ConfigurationInterface) {
|
||||
$configuration = $extension;
|
||||
} elseif ($extension instanceof ConfigurationExtensionInterface) {
|
||||
$container = $this->kernel->getContainer();
|
||||
$configuration = $extension->getConfiguration([], new ContainerBuilder($container instanceof Container ? new ContainerBag($container) : new ParameterBag()));
|
||||
}
|
||||
|
||||
if (!$configuration) {
|
||||
return;
|
||||
}
|
||||
|
||||
$generator->build($configuration);
|
||||
}
|
||||
|
||||
public function isOptional(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
63
vendor/symfony/framework-bundle/CacheWarmer/RouterCacheWarmer.php
vendored
Normal file
63
vendor/symfony/framework-bundle/CacheWarmer/RouterCacheWarmer.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?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\Bundle\FrameworkBundle\CacheWarmer;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
||||
|
||||
/**
|
||||
* Generates the router matcher and generator classes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RouterCacheWarmer implements CacheWarmerInterface, ServiceSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* As this cache warmer is optional, dependencies should be lazy-loaded, that's why a container should be injected.
|
||||
*/
|
||||
public function __construct(
|
||||
private ContainerInterface $container,
|
||||
) {
|
||||
}
|
||||
|
||||
public function warmUp(string $cacheDir, ?string $buildDir = null): array
|
||||
{
|
||||
if (!$buildDir) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$router = $this->container->get('router');
|
||||
|
||||
if ($router instanceof WarmableInterface) {
|
||||
return $router->warmUp($cacheDir, $buildDir);
|
||||
}
|
||||
|
||||
throw new \LogicException(\sprintf('The router "%s" cannot be warmed up because it does not implement "%s".', get_debug_type($router), WarmableInterface::class));
|
||||
}
|
||||
|
||||
public function isOptional(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getSubscribedServices(): array
|
||||
{
|
||||
return [
|
||||
'router' => RouterInterface::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
85
vendor/symfony/framework-bundle/CacheWarmer/SerializerCacheWarmer.php
vendored
Normal file
85
vendor/symfony/framework-bundle/CacheWarmer/SerializerCacheWarmer.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?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\Bundle\FrameworkBundle\CacheWarmer;
|
||||
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory;
|
||||
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\LoaderChain;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\LoaderInterface;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader;
|
||||
use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
|
||||
|
||||
/**
|
||||
* Warms up XML and YAML serializer metadata.
|
||||
*
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* @final since Symfony 7.1
|
||||
*/
|
||||
class SerializerCacheWarmer extends AbstractPhpFileCacheWarmer
|
||||
{
|
||||
/**
|
||||
* @param LoaderInterface[] $loaders The serializer metadata loaders
|
||||
* @param string $phpArrayFile The PHP file where metadata are cached
|
||||
*/
|
||||
public function __construct(
|
||||
private array $loaders,
|
||||
string $phpArrayFile,
|
||||
) {
|
||||
parent::__construct($phpArrayFile);
|
||||
}
|
||||
|
||||
protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter, ?string $buildDir = null): bool
|
||||
{
|
||||
if (!$buildDir) {
|
||||
return false;
|
||||
}
|
||||
if (!$this->loaders) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$metadataFactory = new CacheClassMetadataFactory(new ClassMetadataFactory(new LoaderChain($this->loaders)), $arrayAdapter);
|
||||
|
||||
foreach ($this->extractSupportedLoaders($this->loaders) as $loader) {
|
||||
foreach ($loader->getMappedClasses() as $mappedClass) {
|
||||
try {
|
||||
$metadataFactory->getMetadataFor($mappedClass);
|
||||
} catch (\Exception $e) {
|
||||
$this->ignoreAutoloadException($mappedClass, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LoaderInterface[] $loaders
|
||||
*
|
||||
* @return XmlFileLoader[]|YamlFileLoader[]
|
||||
*/
|
||||
private function extractSupportedLoaders(array $loaders): array
|
||||
{
|
||||
$supportedLoaders = [];
|
||||
|
||||
foreach ($loaders as $loader) {
|
||||
if ($loader instanceof XmlFileLoader || $loader instanceof YamlFileLoader) {
|
||||
$supportedLoaders[] = $loader;
|
||||
} elseif ($loader instanceof LoaderChain) {
|
||||
$supportedLoaders = array_merge($supportedLoaders, $this->extractSupportedLoaders($loader->getLoaders()));
|
||||
}
|
||||
}
|
||||
|
||||
return $supportedLoaders;
|
||||
}
|
||||
}
|
||||
61
vendor/symfony/framework-bundle/CacheWarmer/TranslationsCacheWarmer.php
vendored
Normal file
61
vendor/symfony/framework-bundle/CacheWarmer/TranslationsCacheWarmer.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?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\Bundle\FrameworkBundle\CacheWarmer;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
|
||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Generates the catalogues for translations.
|
||||
*
|
||||
* @author Xavier Leune <xavier.leune@gmail.com>
|
||||
*
|
||||
* @final since Symfony 7.1
|
||||
*/
|
||||
class TranslationsCacheWarmer implements CacheWarmerInterface, ServiceSubscriberInterface
|
||||
{
|
||||
private TranslatorInterface $translator;
|
||||
|
||||
/**
|
||||
* As this cache warmer is optional, dependencies should be lazy-loaded, that's why a container should be injected.
|
||||
*/
|
||||
public function __construct(
|
||||
private ContainerInterface $container,
|
||||
) {
|
||||
}
|
||||
|
||||
public function warmUp(string $cacheDir, ?string $buildDir = null): array
|
||||
{
|
||||
$this->translator ??= $this->container->get('translator');
|
||||
|
||||
if ($this->translator instanceof WarmableInterface) {
|
||||
return $this->translator->warmUp($cacheDir, $buildDir);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function isOptional(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function getSubscribedServices(): array
|
||||
{
|
||||
return [
|
||||
'translator' => TranslatorInterface::class,
|
||||
];
|
||||
}
|
||||
}
|
||||
96
vendor/symfony/framework-bundle/CacheWarmer/ValidatorCacheWarmer.php
vendored
Normal file
96
vendor/symfony/framework-bundle/CacheWarmer/ValidatorCacheWarmer.php
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
<?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\Bundle\FrameworkBundle\CacheWarmer;
|
||||
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
|
||||
use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory;
|
||||
use Symfony\Component\Validator\Mapping\Loader\LoaderChain;
|
||||
use Symfony\Component\Validator\Mapping\Loader\LoaderInterface;
|
||||
use Symfony\Component\Validator\Mapping\Loader\XmlFileLoader;
|
||||
use Symfony\Component\Validator\Mapping\Loader\YamlFileLoader;
|
||||
use Symfony\Component\Validator\ValidatorBuilder;
|
||||
|
||||
/**
|
||||
* Warms up XML and YAML validator metadata.
|
||||
*
|
||||
* @author Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* @final since Symfony 7.1
|
||||
*/
|
||||
class ValidatorCacheWarmer extends AbstractPhpFileCacheWarmer
|
||||
{
|
||||
/**
|
||||
* @param string $phpArrayFile The PHP file where metadata are cached
|
||||
*/
|
||||
public function __construct(
|
||||
private ValidatorBuilder $validatorBuilder,
|
||||
string $phpArrayFile,
|
||||
) {
|
||||
parent::__construct($phpArrayFile);
|
||||
}
|
||||
|
||||
protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter, ?string $buildDir = null): bool
|
||||
{
|
||||
if (!$buildDir) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$loaders = $this->validatorBuilder->getLoaders();
|
||||
$metadataFactory = new LazyLoadingMetadataFactory(new LoaderChain($loaders), $arrayAdapter);
|
||||
|
||||
foreach ($this->extractSupportedLoaders($loaders) as $loader) {
|
||||
foreach ($loader->getMappedClasses() as $mappedClass) {
|
||||
try {
|
||||
if ($metadataFactory->hasMetadataFor($mappedClass)) {
|
||||
$metadataFactory->getMetadataFor($mappedClass);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$this->ignoreAutoloadException($mappedClass, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[] A list of classes to preload on PHP 7.4+
|
||||
*/
|
||||
protected function warmUpPhpArrayAdapter(PhpArrayAdapter $phpArrayAdapter, array $values): array
|
||||
{
|
||||
// make sure we don't cache null values
|
||||
$values = array_filter($values, fn ($val) => null !== $val);
|
||||
|
||||
return parent::warmUpPhpArrayAdapter($phpArrayAdapter, $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LoaderInterface[] $loaders
|
||||
*
|
||||
* @return XmlFileLoader[]|YamlFileLoader[]
|
||||
*/
|
||||
private function extractSupportedLoaders(array $loaders): array
|
||||
{
|
||||
$supportedLoaders = [];
|
||||
|
||||
foreach ($loaders as $loader) {
|
||||
if ($loader instanceof XmlFileLoader || $loader instanceof YamlFileLoader) {
|
||||
$supportedLoaders[] = $loader;
|
||||
} elseif ($loader instanceof LoaderChain) {
|
||||
$supportedLoaders = array_merge($supportedLoaders, $this->extractSupportedLoaders($loader->getLoaders()));
|
||||
}
|
||||
}
|
||||
|
||||
return $supportedLoaders;
|
||||
}
|
||||
}
|
||||
135
vendor/symfony/framework-bundle/Command/AboutCommand.php
vendored
Normal file
135
vendor/symfony/framework-bundle/Command/AboutCommand.php
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\Helper;
|
||||
use Symfony\Component\Console\Helper\TableSeparator;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* A console command to display information about the current installation.
|
||||
*
|
||||
* @author Roland Franssen <franssen.roland@gmail.com>
|
||||
* @author Joppe De Cuyper <hello@joppe.dev>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'about', description: 'Display information about the current project')]
|
||||
class AboutCommand extends Command
|
||||
{
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setHelp(<<<'EOT'
|
||||
The <info>%command.name%</info> command displays information about the current Symfony project.
|
||||
|
||||
The <info>PHP</info> section displays important configuration that could affect your application. The values might
|
||||
be different between web and CLI.
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
if (method_exists($kernel, 'getBuildDir')) {
|
||||
$buildDir = $kernel->getBuildDir();
|
||||
} else {
|
||||
$buildDir = $kernel->getCacheDir();
|
||||
}
|
||||
|
||||
$xdebugMode = getenv('XDEBUG_MODE') ?: \ini_get('xdebug.mode');
|
||||
|
||||
$rows = [
|
||||
['<info>Symfony</>'],
|
||||
new TableSeparator(),
|
||||
['Version', Kernel::VERSION],
|
||||
['Long-Term Support', 4 === Kernel::MINOR_VERSION ? 'Yes' : 'No'],
|
||||
['End of maintenance', Kernel::END_OF_MAINTENANCE.(self::isExpired(Kernel::END_OF_MAINTENANCE) ? ' <error>Expired</>' : ' (<comment>'.self::daysBeforeExpiration(Kernel::END_OF_MAINTENANCE).'</>)')],
|
||||
['End of life', Kernel::END_OF_LIFE.(self::isExpired(Kernel::END_OF_LIFE) ? ' <error>Expired</>' : ' (<comment>'.self::daysBeforeExpiration(Kernel::END_OF_LIFE).'</>)')],
|
||||
new TableSeparator(),
|
||||
['<info>Kernel</>'],
|
||||
new TableSeparator(),
|
||||
['Type', $kernel::class],
|
||||
['Environment', $kernel->getEnvironment()],
|
||||
['Debug', $kernel->isDebug() ? 'true' : 'false'],
|
||||
['Charset', $kernel->getCharset()],
|
||||
['Cache directory', self::formatPath($kernel->getCacheDir(), $kernel->getProjectDir()).' (<comment>'.self::formatFileSize($kernel->getCacheDir()).'</>)'],
|
||||
['Build directory', self::formatPath($buildDir, $kernel->getProjectDir()).' (<comment>'.self::formatFileSize($buildDir).'</>)'],
|
||||
['Log directory', self::formatPath($kernel->getLogDir(), $kernel->getProjectDir()).' (<comment>'.self::formatFileSize($kernel->getLogDir()).'</>)'],
|
||||
new TableSeparator(),
|
||||
['<info>PHP</>'],
|
||||
new TableSeparator(),
|
||||
['Version', \PHP_VERSION],
|
||||
['Architecture', (\PHP_INT_SIZE * 8).' bits'],
|
||||
['Intl locale', class_exists(\Locale::class, false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a'],
|
||||
['Timezone', date_default_timezone_get().' (<comment>'.(new \DateTimeImmutable())->format(\DateTimeInterface::W3C).'</>)'],
|
||||
['OPcache', \extension_loaded('Zend OPcache') ? (filter_var(\ini_get('opcache.enable'), \FILTER_VALIDATE_BOOLEAN) ? 'Enabled' : 'Not enabled') : 'Not installed'],
|
||||
['APCu', \extension_loaded('apcu') ? (filter_var(\ini_get('apc.enabled'), \FILTER_VALIDATE_BOOLEAN) ? 'Enabled' : 'Not enabled') : 'Not installed'],
|
||||
['Xdebug', \extension_loaded('xdebug') ? ($xdebugMode && 'off' !== $xdebugMode ? 'Enabled ('.$xdebugMode.')' : 'Not enabled') : 'Not installed'],
|
||||
];
|
||||
|
||||
$io->table([], $rows);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static function formatPath(string $path, string $baseDir): string
|
||||
{
|
||||
return preg_replace('~^'.preg_quote($baseDir, '~').'~', '.', $path);
|
||||
}
|
||||
|
||||
private static function formatFileSize(string $path): string
|
||||
{
|
||||
if (is_file($path)) {
|
||||
$size = filesize($path) ?: 0;
|
||||
} else {
|
||||
if (!is_dir($path)) {
|
||||
return 'n/a';
|
||||
}
|
||||
|
||||
$size = 0;
|
||||
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS | \RecursiveDirectoryIterator::FOLLOW_SYMLINKS)) as $file) {
|
||||
if ($file->isReadable()) {
|
||||
$size += $file->getSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Helper::formatMemory($size);
|
||||
}
|
||||
|
||||
private static function isExpired(string $date): bool
|
||||
{
|
||||
$date = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.$date);
|
||||
|
||||
return false !== $date && new \DateTimeImmutable() > $date->modify('last day of this month 23:59:59');
|
||||
}
|
||||
|
||||
private static function daysBeforeExpiration(string $date): string
|
||||
{
|
||||
$date = \DateTimeImmutable::createFromFormat('d/m/Y', '01/'.$date);
|
||||
|
||||
return (new \DateTimeImmutable())->diff($date->modify('last day of this month 23:59:59'))->format('in %R%a days');
|
||||
}
|
||||
}
|
||||
189
vendor/symfony/framework-bundle/Command/AbstractConfigCommand.php
vendored
Normal file
189
vendor/symfony/framework-bundle/Command/AbstractConfigCommand.php
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\StyleInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
|
||||
/**
|
||||
* A console command for dumping available configuration reference.
|
||||
*
|
||||
* @author Kevin Bond <kevinbond@gmail.com>
|
||||
* @author Wouter J <waldio.webdesign@gmail.com>
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*/
|
||||
abstract class AbstractConfigCommand extends ContainerDebugCommand
|
||||
{
|
||||
protected function listBundles(OutputInterface|StyleInterface $output): void
|
||||
{
|
||||
$title = 'Available registered bundles with their extension alias if available';
|
||||
$headers = ['Bundle name', 'Extension alias'];
|
||||
$rows = [];
|
||||
|
||||
$bundles = $this->getApplication()->getKernel()->getBundles();
|
||||
usort($bundles, fn ($bundleA, $bundleB) => strcmp($bundleA->getName(), $bundleB->getName()));
|
||||
|
||||
foreach ($bundles as $bundle) {
|
||||
$extension = $bundle->getContainerExtension();
|
||||
$rows[] = [$bundle->getName(), $extension ? $extension->getAlias() : ''];
|
||||
}
|
||||
|
||||
if ($output instanceof StyleInterface) {
|
||||
$output->title($title);
|
||||
$output->table($headers, $rows);
|
||||
} else {
|
||||
$output->writeln($title);
|
||||
$table = new Table($output);
|
||||
$table->setHeaders($headers)->setRows($rows)->render();
|
||||
}
|
||||
}
|
||||
|
||||
protected function listNonBundleExtensions(OutputInterface|StyleInterface $output): void
|
||||
{
|
||||
$title = 'Available registered non-bundle extension aliases';
|
||||
$headers = ['Extension alias'];
|
||||
$rows = [];
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
$bundleExtensions = [];
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
if ($extension = $bundle->getContainerExtension()) {
|
||||
$bundleExtensions[$extension::class] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$extensions = $this->getContainerBuilder($kernel)->getExtensions();
|
||||
|
||||
foreach ($extensions as $alias => $extension) {
|
||||
if (isset($bundleExtensions[$extension::class])) {
|
||||
continue;
|
||||
}
|
||||
$rows[] = [$alias];
|
||||
}
|
||||
|
||||
if (!$rows) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($output instanceof StyleInterface) {
|
||||
$output->title($title);
|
||||
$output->table($headers, $rows);
|
||||
} else {
|
||||
$output->writeln($title);
|
||||
$table = new Table($output);
|
||||
$table->setHeaders($headers)->setRows($rows)->render();
|
||||
}
|
||||
}
|
||||
|
||||
protected function findExtension(string $name): ExtensionInterface
|
||||
{
|
||||
$bundles = $this->initializeBundles();
|
||||
$minScore = \INF;
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
if ($kernel instanceof ExtensionInterface && ($kernel instanceof ConfigurationInterface || $kernel instanceof ConfigurationExtensionInterface)) {
|
||||
if ($name === $kernel->getAlias()) {
|
||||
return $kernel;
|
||||
}
|
||||
|
||||
if ($kernel->getAlias()) {
|
||||
$distance = levenshtein($name, $kernel->getAlias());
|
||||
|
||||
if ($distance < $minScore) {
|
||||
$guess = $kernel->getAlias();
|
||||
$minScore = $distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($bundles as $bundle) {
|
||||
if ($name === $bundle->getName()) {
|
||||
if (!$bundle->getContainerExtension()) {
|
||||
throw new \LogicException(\sprintf('Bundle "%s" does not have a container extension.', $name));
|
||||
}
|
||||
|
||||
return $bundle->getContainerExtension();
|
||||
}
|
||||
|
||||
$distance = levenshtein($name, $bundle->getName());
|
||||
|
||||
if ($distance < $minScore) {
|
||||
$guess = $bundle->getName();
|
||||
$minScore = $distance;
|
||||
}
|
||||
}
|
||||
|
||||
$container = $this->getContainerBuilder($kernel);
|
||||
|
||||
if ($container->hasExtension($name)) {
|
||||
return $container->getExtension($name);
|
||||
}
|
||||
|
||||
foreach ($container->getExtensions() as $extension) {
|
||||
$distance = levenshtein($name, $extension->getAlias());
|
||||
|
||||
if ($distance < $minScore) {
|
||||
$guess = $extension->getAlias();
|
||||
$minScore = $distance;
|
||||
}
|
||||
}
|
||||
|
||||
if (!str_ends_with($name, 'Bundle')) {
|
||||
$message = \sprintf('No extensions with configuration available for "%s".', $name);
|
||||
} else {
|
||||
$message = \sprintf('No extension with alias "%s" is enabled.', $name);
|
||||
}
|
||||
|
||||
if (isset($guess) && $minScore < 3) {
|
||||
$message .= \sprintf("\n\nDid you mean \"%s\"?", $guess);
|
||||
}
|
||||
|
||||
throw new LogicException($message);
|
||||
}
|
||||
|
||||
public function validateConfiguration(ExtensionInterface $extension, mixed $configuration): void
|
||||
{
|
||||
if (!$configuration) {
|
||||
throw new \LogicException(\sprintf('The extension with alias "%s" does not have its getConfiguration() method setup.', $extension->getAlias()));
|
||||
}
|
||||
|
||||
if (!$configuration instanceof ConfigurationInterface) {
|
||||
throw new \LogicException(\sprintf('Configuration class "%s" should implement ConfigurationInterface in order to be dumpable.', get_debug_type($configuration)));
|
||||
}
|
||||
}
|
||||
|
||||
private function initializeBundles(): array
|
||||
{
|
||||
// Re-build bundle manually to initialize DI extensions that can be extended by other bundles in their build() method
|
||||
// as this method is not called when the container is loaded from the cache.
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$container = $this->getContainerBuilder($kernel);
|
||||
$bundles = $kernel->getBundles();
|
||||
foreach ($bundles as $bundle) {
|
||||
if ($extension = $bundle->getContainerExtension()) {
|
||||
$container->registerExtension($extension);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($bundles as $bundle) {
|
||||
$bundle->build($container);
|
||||
}
|
||||
|
||||
return $bundles;
|
||||
}
|
||||
}
|
||||
267
vendor/symfony/framework-bundle/Command/AssetsInstallCommand.php
vendored
Normal file
267
vendor/symfony/framework-bundle/Command/AssetsInstallCommand.php
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* Command that places bundle web assets into a given directory.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Gábor Egyed <gabor.egyed@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'assets:install', description: 'Install bundle\'s web assets under a public directory')]
|
||||
class AssetsInstallCommand extends Command
|
||||
{
|
||||
public const METHOD_COPY = 'copy';
|
||||
public const METHOD_ABSOLUTE_SYMLINK = 'absolute symlink';
|
||||
public const METHOD_RELATIVE_SYMLINK = 'relative symlink';
|
||||
|
||||
public function __construct(
|
||||
private Filesystem $filesystem,
|
||||
private string $projectDir,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('target', InputArgument::OPTIONAL, 'The target directory', null),
|
||||
])
|
||||
->addOption('symlink', null, InputOption::VALUE_NONE, 'Symlink the assets instead of copying them')
|
||||
->addOption('relative', null, InputOption::VALUE_NONE, 'Make relative symlinks')
|
||||
->addOption('no-cleanup', null, InputOption::VALUE_NONE, 'Do not remove the assets of the bundles that no longer exist')
|
||||
->setHelp(<<<'EOT'
|
||||
The <info>%command.name%</info> command installs bundle assets into a given
|
||||
directory (e.g. the <comment>public</comment> directory).
|
||||
|
||||
<info>php %command.full_name% public</info>
|
||||
|
||||
A "bundles" directory will be created inside the target directory and the
|
||||
"Resources/public" directory of each bundle will be copied into it.
|
||||
|
||||
To create a symlink to each bundle instead of copying its assets, use the
|
||||
<info>--symlink</info> option (will fall back to hard copies when symbolic links aren't possible:
|
||||
|
||||
<info>php %command.full_name% public --symlink</info>
|
||||
|
||||
To make symlink relative, add the <info>--relative</info> option:
|
||||
|
||||
<info>php %command.full_name% public --symlink --relative</info>
|
||||
|
||||
EOT
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$targetArg = rtrim($input->getArgument('target') ?? '', '/');
|
||||
if (!$targetArg) {
|
||||
$targetArg = $this->getPublicDirectory($kernel->getContainer());
|
||||
}
|
||||
|
||||
if (!is_dir($targetArg)) {
|
||||
$targetArg = $kernel->getProjectDir().'/'.$targetArg;
|
||||
|
||||
if (!is_dir($targetArg)) {
|
||||
throw new InvalidArgumentException(\sprintf('The target directory "%s" does not exist.', $targetArg));
|
||||
}
|
||||
}
|
||||
|
||||
$bundlesDir = $targetArg.'/bundles/';
|
||||
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->newLine();
|
||||
|
||||
if ($input->getOption('relative')) {
|
||||
$expectedMethod = self::METHOD_RELATIVE_SYMLINK;
|
||||
$io->text('Trying to install assets as <info>relative symbolic links</info>.');
|
||||
} elseif ($input->getOption('symlink')) {
|
||||
$expectedMethod = self::METHOD_ABSOLUTE_SYMLINK;
|
||||
$io->text('Trying to install assets as <info>absolute symbolic links</info>.');
|
||||
} else {
|
||||
$expectedMethod = self::METHOD_COPY;
|
||||
$io->text('Installing assets as <info>hard copies</info>.');
|
||||
}
|
||||
|
||||
$io->newLine();
|
||||
|
||||
$rows = [];
|
||||
$copyUsed = false;
|
||||
$exitCode = 0;
|
||||
$validAssetDirs = [];
|
||||
/** @var BundleInterface $bundle */
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
if (!is_dir($originDir = $bundle->getPath().'/Resources/public') && !is_dir($originDir = $bundle->getPath().'/public')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$assetDir = preg_replace('/bundle$/', '', strtolower($bundle->getName()));
|
||||
$targetDir = $bundlesDir.$assetDir;
|
||||
$validAssetDirs[] = $assetDir;
|
||||
|
||||
if (OutputInterface::VERBOSITY_VERBOSE <= $output->getVerbosity()) {
|
||||
$message = \sprintf("%s\n-> %s", $bundle->getName(), $targetDir);
|
||||
} else {
|
||||
$message = $bundle->getName();
|
||||
}
|
||||
|
||||
try {
|
||||
$this->filesystem->remove($targetDir);
|
||||
|
||||
if (self::METHOD_RELATIVE_SYMLINK === $expectedMethod) {
|
||||
$method = $this->relativeSymlinkWithFallback($originDir, $targetDir);
|
||||
} elseif (self::METHOD_ABSOLUTE_SYMLINK === $expectedMethod) {
|
||||
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
|
||||
} else {
|
||||
$method = $this->hardCopy($originDir, $targetDir);
|
||||
}
|
||||
|
||||
if (self::METHOD_COPY === $method) {
|
||||
$copyUsed = true;
|
||||
}
|
||||
|
||||
if ($method === $expectedMethod) {
|
||||
$rows[] = [\sprintf('<fg=green;options=bold>%s</>', '\\' === \DIRECTORY_SEPARATOR ? 'OK' : "\xE2\x9C\x94" /* HEAVY CHECK MARK (U+2714) */), $message, $method];
|
||||
} else {
|
||||
$rows[] = [\sprintf('<fg=yellow;options=bold>%s</>', '\\' === \DIRECTORY_SEPARATOR ? 'WARNING' : '!'), $message, $method];
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$exitCode = 1;
|
||||
$rows[] = [\sprintf('<fg=red;options=bold>%s</>', '\\' === \DIRECTORY_SEPARATOR ? 'ERROR' : "\xE2\x9C\x98" /* HEAVY BALLOT X (U+2718) */), $message, $e->getMessage()];
|
||||
}
|
||||
}
|
||||
// remove the assets of the bundles that no longer exist
|
||||
if (!$input->getOption('no-cleanup') && is_dir($bundlesDir)) {
|
||||
$dirsToRemove = Finder::create()->depth(0)->directories()->exclude($validAssetDirs)->in($bundlesDir);
|
||||
$this->filesystem->remove($dirsToRemove);
|
||||
}
|
||||
|
||||
if ($rows) {
|
||||
$io->table(['', 'Bundle', 'Method / Error'], $rows);
|
||||
}
|
||||
|
||||
if (0 !== $exitCode) {
|
||||
$io->error('Some errors occurred while installing assets.');
|
||||
} else {
|
||||
if ($copyUsed) {
|
||||
$io->note('Some assets were installed via copy. If you make changes to these assets you have to run this command again.');
|
||||
}
|
||||
$io->success($rows ? 'All assets were successfully installed.' : 'No assets were provided by any bundle.');
|
||||
}
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to create relative symlink.
|
||||
*
|
||||
* Falling back to absolute symlink and finally hard copy.
|
||||
*/
|
||||
private function relativeSymlinkWithFallback(string $originDir, string $targetDir): string
|
||||
{
|
||||
try {
|
||||
$this->symlink($originDir, $targetDir, true);
|
||||
$method = self::METHOD_RELATIVE_SYMLINK;
|
||||
} catch (IOException) {
|
||||
$method = $this->absoluteSymlinkWithFallback($originDir, $targetDir);
|
||||
}
|
||||
|
||||
return $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to create absolute symlink.
|
||||
*
|
||||
* Falling back to hard copy.
|
||||
*/
|
||||
private function absoluteSymlinkWithFallback(string $originDir, string $targetDir): string
|
||||
{
|
||||
try {
|
||||
$this->symlink($originDir, $targetDir);
|
||||
$method = self::METHOD_ABSOLUTE_SYMLINK;
|
||||
} catch (IOException) {
|
||||
// fall back to copy
|
||||
$method = $this->hardCopy($originDir, $targetDir);
|
||||
}
|
||||
|
||||
return $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates symbolic link.
|
||||
*
|
||||
* @throws IOException if link cannot be created
|
||||
*/
|
||||
private function symlink(string $originDir, string $targetDir, bool $relative = false): void
|
||||
{
|
||||
if ($relative) {
|
||||
$this->filesystem->mkdir(\dirname($targetDir));
|
||||
$originDir = $this->filesystem->makePathRelative($originDir, realpath(\dirname($targetDir)));
|
||||
}
|
||||
$this->filesystem->symlink($originDir, $targetDir);
|
||||
if (!file_exists($targetDir)) {
|
||||
throw new IOException(\sprintf('Symbolic link "%s" was created but appears to be broken.', $targetDir), 0, null, $targetDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies origin to target.
|
||||
*/
|
||||
private function hardCopy(string $originDir, string $targetDir): string
|
||||
{
|
||||
$this->filesystem->mkdir($targetDir, 0777);
|
||||
// We use a custom iterator to ignore VCS files
|
||||
$this->filesystem->mirror($originDir, $targetDir, Finder::create()->ignoreDotFiles(false)->in($originDir));
|
||||
|
||||
return self::METHOD_COPY;
|
||||
}
|
||||
|
||||
private function getPublicDirectory(ContainerInterface $container): string
|
||||
{
|
||||
$defaultPublicDir = 'public';
|
||||
|
||||
if (null === $this->projectDir && !$container->hasParameter('kernel.project_dir')) {
|
||||
return $defaultPublicDir;
|
||||
}
|
||||
|
||||
$composerFilePath = ($this->projectDir ?? $container->getParameter('kernel.project_dir')).'/composer.json';
|
||||
|
||||
if (!file_exists($composerFilePath)) {
|
||||
return $defaultPublicDir;
|
||||
}
|
||||
|
||||
$composerConfig = json_decode($this->filesystem->readFile($composerFilePath), true, flags: \JSON_THROW_ON_ERROR);
|
||||
|
||||
return $composerConfig['extra']['public-dir'] ?? $defaultPublicDir;
|
||||
}
|
||||
}
|
||||
71
vendor/symfony/framework-bundle/Command/BuildDebugContainerTrait.php
vendored
Normal file
71
vendor/symfony/framework-bundle/Command/BuildDebugContainerTrait.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Config\ConfigCache;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
trait BuildDebugContainerTrait
|
||||
{
|
||||
protected ContainerBuilder $container;
|
||||
|
||||
/**
|
||||
* Loads the ContainerBuilder from the cache.
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function getContainerBuilder(KernelInterface $kernel): ContainerBuilder
|
||||
{
|
||||
if (isset($this->container)) {
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
if (!$kernel->isDebug() || !$kernel->getContainer()->getParameter('debug.container.dump') || !(new ConfigCache($kernel->getContainer()->getParameter('debug.container.dump'), true))->isFresh()) {
|
||||
$buildContainer = \Closure::bind(function () {
|
||||
$this->initializeBundles();
|
||||
|
||||
return $this->buildContainer();
|
||||
}, $kernel, $kernel::class);
|
||||
$container = $buildContainer();
|
||||
$container->getCompilerPassConfig()->setRemovingPasses([]);
|
||||
$container->getCompilerPassConfig()->setAfterRemovingPasses([]);
|
||||
$container->compile();
|
||||
} else {
|
||||
$buildContainer = \Closure::bind(function () {
|
||||
$containerBuilder = $this->getContainerBuilder();
|
||||
$this->prepareContainer($containerBuilder);
|
||||
|
||||
return $containerBuilder;
|
||||
}, $kernel, $kernel::class);
|
||||
$container = $buildContainer();
|
||||
(new XmlFileLoader($container, new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump'));
|
||||
$locatorPass = new ServiceLocatorTagPass();
|
||||
$locatorPass->process($container);
|
||||
|
||||
$container->getCompilerPassConfig()->setBeforeOptimizationPasses([]);
|
||||
$container->getCompilerPassConfig()->setOptimizationPasses([]);
|
||||
$container->getCompilerPassConfig()->setBeforeRemovingPasses([]);
|
||||
}
|
||||
|
||||
return $this->container = $container;
|
||||
}
|
||||
}
|
||||
254
vendor/symfony/framework-bundle/Command/CacheClearCommand.php
vendored
Normal file
254
vendor/symfony/framework-bundle/Command/CacheClearCommand.php
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\Dumper\Preloader;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
use Symfony\Component\Filesystem\Exception\IOException;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
|
||||
use Symfony\Component\HttpKernel\RebootableInterface;
|
||||
|
||||
/**
|
||||
* Clear and Warmup the cache.
|
||||
*
|
||||
* @author Francis Besset <francis.besset@gmail.com>
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'cache:clear', description: 'Clear the cache')]
|
||||
class CacheClearCommand extends Command
|
||||
{
|
||||
private Filesystem $filesystem;
|
||||
|
||||
public function __construct(
|
||||
private CacheClearerInterface $cacheClearer,
|
||||
?Filesystem $filesystem = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->filesystem = $filesystem ?? new Filesystem();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputOption('no-warmup', '', InputOption::VALUE_NONE, 'Do not warm up the cache'),
|
||||
new InputOption('no-optional-warmers', '', InputOption::VALUE_NONE, 'Skip optional cache warmers (faster)'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command clears and warms up the application cache for a given environment
|
||||
and debug mode:
|
||||
|
||||
<info>php %command.full_name% --env=dev</info>
|
||||
<info>php %command.full_name% --env=prod --no-debug</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$fs = $this->filesystem;
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$realCacheDir = $kernel->getContainer()->getParameter('kernel.cache_dir');
|
||||
$realBuildDir = $kernel->getContainer()->hasParameter('kernel.build_dir') ? $kernel->getContainer()->getParameter('kernel.build_dir') : $realCacheDir;
|
||||
// the old cache dir name must not be longer than the real one to avoid exceeding
|
||||
// the maximum length of a directory or file path within it (esp. Windows MAX_PATH)
|
||||
$oldCacheDir = substr($realCacheDir, 0, -1).(str_ends_with($realCacheDir, '~') ? '+' : '~');
|
||||
$fs->remove($oldCacheDir);
|
||||
|
||||
if (!is_writable($realCacheDir)) {
|
||||
throw new RuntimeException(\sprintf('Unable to write in the "%s" directory.', $realCacheDir));
|
||||
}
|
||||
|
||||
$useBuildDir = $realBuildDir !== $realCacheDir;
|
||||
$oldBuildDir = substr($realBuildDir, 0, -1).(str_ends_with($realBuildDir, '~') ? '+' : '~');
|
||||
if ($useBuildDir) {
|
||||
$fs->remove($oldBuildDir);
|
||||
|
||||
if (!is_writable($realBuildDir)) {
|
||||
throw new RuntimeException(\sprintf('Unable to write in the "%s" directory.', $realBuildDir));
|
||||
}
|
||||
|
||||
if ($this->isNfs($realCacheDir)) {
|
||||
$fs->remove($realCacheDir);
|
||||
} else {
|
||||
$fs->rename($realCacheDir, $oldCacheDir);
|
||||
}
|
||||
$fs->mkdir($realCacheDir);
|
||||
}
|
||||
|
||||
$io->comment(\sprintf('Clearing the cache for the <info>%s</info> environment with debug <info>%s</info>', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
|
||||
if ($useBuildDir) {
|
||||
$this->cacheClearer->clear($realBuildDir);
|
||||
}
|
||||
$this->cacheClearer->clear($realCacheDir);
|
||||
|
||||
// The current event dispatcher is stale, let's not use it anymore
|
||||
$this->getApplication()->setDispatcher(new EventDispatcher());
|
||||
|
||||
$containerFile = (new \ReflectionObject($kernel->getContainer()))->getFileName();
|
||||
$containerDir = basename(\dirname($containerFile));
|
||||
|
||||
// the warmup cache dir name must have the same length as the real one
|
||||
// to avoid the many problems in serialized resources files
|
||||
$warmupDir = substr($realBuildDir, 0, -1).(str_ends_with($realBuildDir, '_') ? '-' : '_');
|
||||
|
||||
if ($output->isVerbose() && $fs->exists($warmupDir)) {
|
||||
$io->comment('Clearing outdated warmup directory...');
|
||||
}
|
||||
$fs->remove($warmupDir);
|
||||
|
||||
if ($_SERVER['REQUEST_TIME'] <= filemtime($containerFile) && filemtime($containerFile) <= time()) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Cache is fresh.');
|
||||
}
|
||||
if (!$input->getOption('no-warmup') && !$input->getOption('no-optional-warmers')) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Warming up optional cache...');
|
||||
}
|
||||
$this->warmupOptionals($realCacheDir, $realBuildDir, $io);
|
||||
}
|
||||
} else {
|
||||
$fs->mkdir($warmupDir);
|
||||
|
||||
if (!$input->getOption('no-warmup')) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Warming up cache...');
|
||||
}
|
||||
$this->warmup($warmupDir, $realBuildDir);
|
||||
|
||||
if (!$input->getOption('no-optional-warmers')) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Warming up optional cache...');
|
||||
}
|
||||
$this->warmupOptionals($useBuildDir ? $realCacheDir : $warmupDir, $warmupDir, $io);
|
||||
}
|
||||
|
||||
// fix references to cached files with the real cache directory name
|
||||
$search = [$warmupDir, str_replace('/', '\\/', $warmupDir), str_replace('\\', '\\\\', $warmupDir)];
|
||||
$replace = str_replace('\\', '/', $realBuildDir);
|
||||
foreach (Finder::create()->files()->in($warmupDir) as $file) {
|
||||
$content = str_replace($search, $replace, $this->filesystem->readFile($file), $count);
|
||||
if ($count) {
|
||||
file_put_contents($file, $content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$fs->exists($warmupDir.'/'.$containerDir)) {
|
||||
$fs->rename($realBuildDir.'/'.$containerDir, $warmupDir.'/'.$containerDir);
|
||||
touch($warmupDir.'/'.$containerDir.'.legacy');
|
||||
}
|
||||
|
||||
if ($this->isNfs($realBuildDir)) {
|
||||
$io->note('For better performance, you should move the cache and log directories to a non-shared folder of the VM.');
|
||||
$fs->remove($realBuildDir);
|
||||
} else {
|
||||
$fs->rename($realBuildDir, $oldBuildDir);
|
||||
}
|
||||
|
||||
$fs->rename($warmupDir, $realBuildDir);
|
||||
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Removing old build and cache directory...');
|
||||
}
|
||||
|
||||
if ($useBuildDir) {
|
||||
try {
|
||||
$fs->remove($oldBuildDir);
|
||||
} catch (IOException $e) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->warning($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$fs->remove($oldCacheDir);
|
||||
} catch (IOException $e) {
|
||||
if ($output->isVerbose()) {
|
||||
$io->warning($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($output->isVerbose()) {
|
||||
$io->comment('Finished');
|
||||
}
|
||||
|
||||
$io->success(\sprintf('Cache for the "%s" environment (debug=%s) was successfully cleared.', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function isNfs(string $dir): bool
|
||||
{
|
||||
static $mounts = null;
|
||||
|
||||
if (null === $mounts) {
|
||||
$mounts = [];
|
||||
if ('/' === \DIRECTORY_SEPARATOR && @is_readable('/proc/mounts') && $files = @file('/proc/mounts')) {
|
||||
foreach ($files as $mount) {
|
||||
$mount = \array_slice(explode(' ', $mount), 1, -3);
|
||||
if (!\in_array(array_pop($mount), ['vboxsf', 'nfs'])) {
|
||||
continue;
|
||||
}
|
||||
$mounts[] = implode(' ', $mount).'/';
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($mounts as $mount) {
|
||||
if (str_starts_with($dir, $mount)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function warmup(string $warmupDir, string $realBuildDir): void
|
||||
{
|
||||
// create a temporary kernel
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
if (!$kernel instanceof RebootableInterface) {
|
||||
throw new \LogicException('Calling "cache:clear" with a kernel that does not implement "Symfony\Component\HttpKernel\RebootableInterface" is not supported.');
|
||||
}
|
||||
$kernel->reboot($warmupDir);
|
||||
}
|
||||
|
||||
private function warmupOptionals(string $cacheDir, string $warmupDir, SymfonyStyle $io): void
|
||||
{
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$warmer = $kernel->getContainer()->get('cache_warmer');
|
||||
// non optional warmers already ran during container compilation
|
||||
$warmer->enableOnlyOptionalWarmers();
|
||||
$preload = (array) $warmer->warmUp($cacheDir, $warmupDir, $io);
|
||||
|
||||
if ($preload && file_exists($preloadFile = $warmupDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) {
|
||||
Preloader::append($preloadFile, $preload);
|
||||
}
|
||||
}
|
||||
}
|
||||
140
vendor/symfony/framework-bundle/Command/CachePoolClearCommand.php
vendored
Normal file
140
vendor/symfony/framework-bundle/Command/CachePoolClearCommand.php
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
|
||||
|
||||
/**
|
||||
* Clear cache pools.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
#[AsCommand(name: 'cache:pool:clear', description: 'Clear cache pools')]
|
||||
final class CachePoolClearCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @param string[]|null $poolNames
|
||||
*/
|
||||
public function __construct(
|
||||
private Psr6CacheClearer $poolClearer,
|
||||
private ?array $poolNames = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('pools', InputArgument::IS_ARRAY | InputArgument::OPTIONAL, 'A list of cache pools or cache pool clearers'),
|
||||
])
|
||||
->addOption('all', null, InputOption::VALUE_NONE, 'Clear all cache pools')
|
||||
->addOption('exclude', null, InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, 'A list of cache pools or cache pool clearers to exclude')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command clears the given cache pools or cache pool clearers.
|
||||
|
||||
%command.full_name% <cache pool or clearer 1> [...<cache pool or clearer N>]
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$pools = [];
|
||||
$clearers = [];
|
||||
|
||||
$poolNames = $input->getArgument('pools');
|
||||
$excludedPoolNames = $input->getOption('exclude');
|
||||
if ($clearAll = $input->getOption('all')) {
|
||||
if (!$this->poolNames) {
|
||||
throw new InvalidArgumentException('Could not clear all cache pools, try specifying a specific pool or cache clearer.');
|
||||
}
|
||||
|
||||
if (!$excludedPoolNames) {
|
||||
$io->comment('Clearing all cache pools...');
|
||||
}
|
||||
|
||||
$poolNames = $this->poolNames;
|
||||
} elseif (!$poolNames) {
|
||||
throw new InvalidArgumentException('Either specify at least one pool name, or provide the --all option to clear all pools.');
|
||||
}
|
||||
|
||||
$poolNames = array_diff($poolNames, $excludedPoolNames);
|
||||
|
||||
foreach ($poolNames as $id) {
|
||||
if ($this->poolClearer->hasPool($id)) {
|
||||
$pools[$id] = $id;
|
||||
} elseif (!$clearAll || $kernel->getContainer()->has($id)) {
|
||||
$pool = $kernel->getContainer()->get($id);
|
||||
|
||||
if ($pool instanceof CacheItemPoolInterface) {
|
||||
$pools[$id] = $pool;
|
||||
} elseif ($pool instanceof Psr6CacheClearer) {
|
||||
$clearers[$id] = $pool;
|
||||
} else {
|
||||
throw new InvalidArgumentException(\sprintf('"%s" is not a cache pool nor a cache clearer.', $id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($clearers as $id => $clearer) {
|
||||
$io->comment(\sprintf('Calling cache clearer: <info>%s</info>', $id));
|
||||
$clearer->clear($kernel->getContainer()->getParameter('kernel.cache_dir'));
|
||||
}
|
||||
|
||||
$failure = false;
|
||||
foreach ($pools as $id => $pool) {
|
||||
$io->comment(\sprintf('Clearing cache pool: <info>%s</info>', $id));
|
||||
|
||||
if ($pool instanceof CacheItemPoolInterface) {
|
||||
if (!$pool->clear()) {
|
||||
$io->warning(\sprintf('Cache pool "%s" could not be cleared.', $pool));
|
||||
$failure = true;
|
||||
}
|
||||
} else {
|
||||
if (false === $this->poolClearer->clearPool($id)) {
|
||||
$io->warning(\sprintf('Cache pool "%s" could not be cleared.', $pool));
|
||||
$failure = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($failure) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
$io->success('Cache was successfully cleared.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if (\is_array($this->poolNames) && $input->mustSuggestArgumentValuesFor('pools')) {
|
||||
$suggestions->suggestValues($this->poolNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
86
vendor/symfony/framework-bundle/Command/CachePoolDeleteCommand.php
vendored
Normal file
86
vendor/symfony/framework-bundle/Command/CachePoolDeleteCommand.php
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
|
||||
|
||||
/**
|
||||
* Delete an item from a cache pool.
|
||||
*
|
||||
* @author Pierre du Plessis <pdples@gmail.com>
|
||||
*/
|
||||
#[AsCommand(name: 'cache:pool:delete', description: 'Delete an item from a cache pool')]
|
||||
final class CachePoolDeleteCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @param string[]|null $poolNames
|
||||
*/
|
||||
public function __construct(
|
||||
private Psr6CacheClearer $poolClearer,
|
||||
private ?array $poolNames = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('pool', InputArgument::REQUIRED, 'The cache pool from which to delete an item'),
|
||||
new InputArgument('key', InputArgument::REQUIRED, 'The cache key to delete from the pool'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> deletes an item from a given cache pool.
|
||||
|
||||
%command.full_name% <pool> <key>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$pool = $input->getArgument('pool');
|
||||
$key = $input->getArgument('key');
|
||||
$cachePool = $this->poolClearer->getPool($pool);
|
||||
|
||||
if (!$cachePool->hasItem($key)) {
|
||||
$io->note(\sprintf('Cache item "%s" does not exist in cache pool "%s".', $key, $pool));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!$cachePool->deleteItem($key)) {
|
||||
throw new \Exception(\sprintf('Cache item "%s" could not be deleted.', $key));
|
||||
}
|
||||
|
||||
$io->success(\sprintf('Cache item "%s" was successfully deleted.', $key));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if (\is_array($this->poolNames) && $input->mustSuggestArgumentValuesFor('pool')) {
|
||||
$suggestions->suggestValues($this->poolNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
108
vendor/symfony/framework-bundle/Command/CachePoolInvalidateTagsCommand.php
vendored
Normal file
108
vendor/symfony/framework-bundle/Command/CachePoolInvalidateTagsCommand.php
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
||||
use Symfony\Contracts\Service\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* @author Kevin Bond <kevinbond@gmail.com>
|
||||
*/
|
||||
#[AsCommand(name: 'cache:pool:invalidate-tags', description: 'Invalidate cache tags for all or a specific pool')]
|
||||
final class CachePoolInvalidateTagsCommand extends Command
|
||||
{
|
||||
private array $poolNames;
|
||||
|
||||
public function __construct(
|
||||
private ServiceProviderInterface $pools,
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
$this->poolNames = array_keys($pools->getProvidedServices());
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('tags', InputArgument::IS_ARRAY | InputArgument::REQUIRED, 'The tags to invalidate')
|
||||
->addOption('pool', 'p', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'The pools to invalidate on')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command invalidates tags from taggable pools. By default, all pools
|
||||
have the passed tags invalidated. Pass <info>--pool=my_pool</info> to invalidate tags on a specific pool.
|
||||
|
||||
php %command.full_name% tag1 tag2
|
||||
php %command.full_name% tag1 tag2 --pool=cache2 --pool=cache1
|
||||
EOF)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$pools = $input->getOption('pool') ?: $this->poolNames;
|
||||
$tags = $input->getArgument('tags');
|
||||
$tagList = implode(', ', $tags);
|
||||
$errors = false;
|
||||
|
||||
foreach ($pools as $name) {
|
||||
$io->comment(\sprintf('Invalidating tag(s): <info>%s</info> from pool <comment>%s</comment>.', $tagList, $name));
|
||||
|
||||
try {
|
||||
$pool = $this->pools->get($name);
|
||||
} catch (ServiceNotFoundException) {
|
||||
$io->error(\sprintf('Pool "%s" not found.', $name));
|
||||
$errors = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$pool instanceof TagAwareCacheInterface) {
|
||||
$io->error(\sprintf('Pool "%s" is not taggable.', $name));
|
||||
$errors = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$pool->invalidateTags($tags)) {
|
||||
$io->error(\sprintf('Cache tag(s) "%s" could not be invalidated for pool "%s".', $tagList, $name));
|
||||
$errors = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
$io->error('Done but with errors.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$io->success('Successfully invalidated cache tags.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestOptionValuesFor('pool')) {
|
||||
$suggestions->suggestValues($this->poolNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
55
vendor/symfony/framework-bundle/Command/CachePoolListCommand.php
vendored
Normal file
55
vendor/symfony/framework-bundle/Command/CachePoolListCommand.php
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* List available cache pools.
|
||||
*
|
||||
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
*/
|
||||
#[AsCommand(name: 'cache:pool:list', description: 'List available cache pools')]
|
||||
final class CachePoolListCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @param string[] $poolNames
|
||||
*/
|
||||
public function __construct(
|
||||
private array $poolNames,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command lists all available cache pools.
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$io->table(['Pool name'], array_map(fn ($pool) => [$pool], $this->poolNames));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
63
vendor/symfony/framework-bundle/Command/CachePoolPruneCommand.php
vendored
Normal file
63
vendor/symfony/framework-bundle/Command/CachePoolPruneCommand.php
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Cache\PruneableInterface;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* Cache pool pruner command.
|
||||
*
|
||||
* @author Rob Frawley 2nd <rmf@src.run>
|
||||
*/
|
||||
#[AsCommand(name: 'cache:pool:prune', description: 'Prune cache pools')]
|
||||
final class CachePoolPruneCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @param iterable<mixed, PruneableInterface> $pools
|
||||
*/
|
||||
public function __construct(
|
||||
private iterable $pools,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command deletes all expired items from all pruneable pools.
|
||||
|
||||
%command.full_name%
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
foreach ($this->pools as $name => $pool) {
|
||||
$io->comment(\sprintf('Pruning cache pool: <info>%s</info>', $name));
|
||||
$pool->prune();
|
||||
}
|
||||
|
||||
$io->success('Successfully pruned cache pool(s).');
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
84
vendor/symfony/framework-bundle/Command/CacheWarmupCommand.php
vendored
Normal file
84
vendor/symfony/framework-bundle/Command/CacheWarmupCommand.php
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\Dumper\Preloader;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate;
|
||||
use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
|
||||
|
||||
/**
|
||||
* Warmup the cache.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'cache:warmup', description: 'Warm up an empty cache')]
|
||||
class CacheWarmupCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private CacheWarmerAggregate $cacheWarmer,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputOption('no-optional-warmers', '', InputOption::VALUE_NONE, 'Skip optional cache warmers (faster)'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command warms up the cache.
|
||||
|
||||
Before running this command, the cache must be empty.
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$io->comment(\sprintf('Warming up the cache for the <info>%s</info> environment with debug <info>%s</info>', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
|
||||
|
||||
if (!$input->getOption('no-optional-warmers')) {
|
||||
$this->cacheWarmer->enableOptionalWarmers();
|
||||
}
|
||||
$cacheDir = $kernel->getContainer()->getParameter('kernel.cache_dir');
|
||||
|
||||
if ($kernel instanceof WarmableInterface) {
|
||||
$kernel->warmUp($cacheDir);
|
||||
}
|
||||
|
||||
$buildDir = $kernel->getContainer()->getParameter('kernel.build_dir');
|
||||
|
||||
$preload = $this->cacheWarmer->warmUp($cacheDir, $buildDir);
|
||||
|
||||
if ($preload && $cacheDir === $buildDir && file_exists($preloadFile = $buildDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) {
|
||||
Preloader::append($preloadFile, $preload);
|
||||
}
|
||||
|
||||
$io->success(\sprintf('Cache for the "%s" environment (debug=%s) was successfully warmed.', $kernel->getEnvironment(), var_export($kernel->isDebug(), true)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
287
vendor/symfony/framework-bundle/Command/ConfigDebugCommand.php
vendored
Normal file
287
vendor/symfony/framework-bundle/Command/ConfigDebugCommand.php
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Config\Definition\Processor;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ValidateEnvPlaceholdersPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
|
||||
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* A console command for dumping available configuration reference.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'debug:config', description: 'Dump the current configuration for an extension')]
|
||||
class ConfigDebugCommand extends AbstractConfigCommand
|
||||
{
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('name', InputArgument::OPTIONAL, 'The bundle name or the extension alias'),
|
||||
new InputArgument('path', InputArgument::OPTIONAL, 'The configuration option path'),
|
||||
new InputOption('resolve-env', null, InputOption::VALUE_NONE, 'Display resolved environment variable values instead of placeholders'),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), class_exists(Yaml::class) ? 'txt' : 'json'),
|
||||
])
|
||||
->setHelp(<<<EOF
|
||||
The <info>%command.name%</info> command dumps the current configuration for an
|
||||
extension/bundle.
|
||||
|
||||
Either the extension alias or bundle name can be used:
|
||||
|
||||
<info>php %command.full_name% framework</info>
|
||||
<info>php %command.full_name% FrameworkBundle</info>
|
||||
|
||||
The <info>--format</info> option specifies the format of the command output:
|
||||
|
||||
<info>php %command.full_name% framework --format=json</info>
|
||||
|
||||
For dumping a specific option, add its path as second argument:
|
||||
|
||||
<info>php %command.full_name% framework serializer.enabled</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
if (null === $name = $input->getArgument('name')) {
|
||||
$this->listBundles($errorIo);
|
||||
$this->listNonBundleExtensions($errorIo);
|
||||
|
||||
$errorIo->comment('Provide the name of a bundle as the first argument of this command to dump its configuration. (e.g. <comment>debug:config FrameworkBundle</comment>)');
|
||||
$errorIo->comment('For dumping a specific option, add its path as the second argument of this command. (e.g. <comment>debug:config FrameworkBundle serializer</comment> to dump the <comment>framework.serializer</comment> configuration)');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$extension = $this->findExtension($name);
|
||||
$extensionAlias = $extension->getAlias();
|
||||
$container = $this->compileContainer();
|
||||
|
||||
$config = $this->getConfig($extension, $container, $input->getOption('resolve-env'));
|
||||
|
||||
$format = $input->getOption('format');
|
||||
|
||||
if (\in_array($format, ['txt', 'yml'], true) && !class_exists(Yaml::class)) {
|
||||
$errorIo->error('Setting the "format" option to "txt" or "yaml" requires the Symfony Yaml component. Try running "composer install symfony/yaml" or use "--format=json" instead.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (null === $path = $input->getArgument('path')) {
|
||||
if ('txt' === $input->getOption('format')) {
|
||||
$io->title(
|
||||
\sprintf('Current configuration for %s', $name === $extensionAlias ? \sprintf('extension with alias "%s"', $extensionAlias) : \sprintf('"%s"', $name))
|
||||
);
|
||||
|
||||
if ($docUrl = $this->getDocUrl($extension, $container)) {
|
||||
$io->comment(\sprintf('Documentation at %s', $docUrl));
|
||||
}
|
||||
}
|
||||
|
||||
$io->writeln($this->convertToFormat([$extensionAlias => $config], $format));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
$config = $this->getConfigForPath($config, $path, $extensionAlias);
|
||||
} catch (LogicException $e) {
|
||||
$errorIo->error($e->getMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$io->title(\sprintf('Current configuration for "%s.%s"', $extensionAlias, $path));
|
||||
|
||||
$io->writeln($this->convertToFormat($config, $format));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function convertToFormat(mixed $config, string $format): string
|
||||
{
|
||||
return match ($format) {
|
||||
'txt', 'yaml' => Yaml::dump($config, 10),
|
||||
'json' => json_encode($config, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE),
|
||||
default => throw new InvalidArgumentException(\sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions()))),
|
||||
};
|
||||
}
|
||||
|
||||
private function compileContainer(): ContainerBuilder
|
||||
{
|
||||
$kernel = clone $this->getApplication()->getKernel();
|
||||
$kernel->boot();
|
||||
|
||||
$method = new \ReflectionMethod($kernel, 'buildContainer');
|
||||
$container = $method->invoke($kernel);
|
||||
$container->getCompiler()->compile($container);
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over configuration until the last step of the given path.
|
||||
*
|
||||
* @throws LogicException If the configuration does not exist
|
||||
*/
|
||||
private function getConfigForPath(array $config, string $path, string $alias): mixed
|
||||
{
|
||||
$steps = explode('.', $path);
|
||||
|
||||
foreach ($steps as $step) {
|
||||
if (!\array_key_exists($step, $config)) {
|
||||
throw new LogicException(\sprintf('Unable to find configuration for "%s.%s".', $alias, $path));
|
||||
}
|
||||
|
||||
$config = $config[$step];
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
private function getConfigForExtension(ExtensionInterface $extension, ContainerBuilder $container): array
|
||||
{
|
||||
$extensionAlias = $extension->getAlias();
|
||||
|
||||
$extensionConfig = [];
|
||||
foreach ($container->getCompilerPassConfig()->getPasses() as $pass) {
|
||||
if ($pass instanceof ValidateEnvPlaceholdersPass) {
|
||||
$extensionConfig = $pass->getExtensionConfig();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($extensionConfig[$extensionAlias])) {
|
||||
return $extensionConfig[$extensionAlias];
|
||||
}
|
||||
|
||||
// Fall back to default config if the extension has one
|
||||
|
||||
if (!$extension instanceof ConfigurationExtensionInterface && !$extension instanceof ConfigurationInterface) {
|
||||
throw new \LogicException(\sprintf('The extension with alias "%s" does not have configuration.', $extensionAlias));
|
||||
}
|
||||
|
||||
$configs = $container->getExtensionConfig($extensionAlias);
|
||||
$configuration = $extension instanceof ConfigurationInterface ? $extension : $extension->getConfiguration($configs, $container);
|
||||
$this->validateConfiguration($extension, $configuration);
|
||||
|
||||
return (new Processor())->processConfiguration($configuration, $configs);
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('name')) {
|
||||
$suggestions->suggestValues($this->getAvailableExtensions());
|
||||
$suggestions->suggestValues($this->getAvailableBundles());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestArgumentValuesFor('path') && null !== $name = $input->getArgument('name')) {
|
||||
try {
|
||||
$config = $this->getConfig($this->findExtension($name), $this->compileContainer());
|
||||
$paths = array_keys(self::buildPathsCompletion($config));
|
||||
$suggestions->suggestValues($paths);
|
||||
} catch (LogicException) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues($this->getAvailableFormatOptions());
|
||||
}
|
||||
}
|
||||
|
||||
private function getAvailableExtensions(): array
|
||||
{
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
$extensions = [];
|
||||
foreach ($this->getContainerBuilder($kernel)->getExtensions() as $alias => $extension) {
|
||||
$extensions[] = $alias;
|
||||
}
|
||||
|
||||
return $extensions;
|
||||
}
|
||||
|
||||
private function getAvailableBundles(): array
|
||||
{
|
||||
$availableBundles = [];
|
||||
foreach ($this->getApplication()->getKernel()->getBundles() as $bundle) {
|
||||
$availableBundles[] = $bundle->getName();
|
||||
}
|
||||
|
||||
return $availableBundles;
|
||||
}
|
||||
|
||||
private function getConfig(ExtensionInterface $extension, ContainerBuilder $container, bool $resolveEnvs = false): mixed
|
||||
{
|
||||
return $container->resolveEnvPlaceholders(
|
||||
$container->getParameterBag()->resolveValue(
|
||||
$this->getConfigForExtension($extension, $container)
|
||||
), $resolveEnvs ?: null
|
||||
);
|
||||
}
|
||||
|
||||
private static function buildPathsCompletion(array $paths, string $prefix = ''): array
|
||||
{
|
||||
$completionPaths = [];
|
||||
foreach ($paths as $key => $values) {
|
||||
if (\is_array($values)) {
|
||||
$completionPaths += self::buildPathsCompletion($values, $prefix.$key.'.');
|
||||
} else {
|
||||
$completionPaths[$prefix.$key] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $completionPaths;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function getAvailableFormatOptions(): array
|
||||
{
|
||||
return ['txt', 'yaml', 'json'];
|
||||
}
|
||||
|
||||
private function getDocUrl(ExtensionInterface $extension, ContainerBuilder $container): ?string
|
||||
{
|
||||
$configuration = $extension instanceof ConfigurationInterface ? $extension : $extension->getConfiguration($container->getExtensionConfig($extension->getAlias()), $container);
|
||||
|
||||
return $configuration
|
||||
->getConfigTreeBuilder()
|
||||
->getRootNode()
|
||||
->getNode(true)
|
||||
->getAttribute('docUrl');
|
||||
}
|
||||
}
|
||||
204
vendor/symfony/framework-bundle/Command/ConfigDumpReferenceCommand.php
vendored
Normal file
204
vendor/symfony/framework-bundle/Command/ConfigDumpReferenceCommand.php
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Config\Definition\ConfigurationInterface;
|
||||
use Symfony\Component\Config\Definition\Dumper\XmlReferenceDumper;
|
||||
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* A console command for dumping available configuration reference.
|
||||
*
|
||||
* @author Kevin Bond <kevinbond@gmail.com>
|
||||
* @author Wouter J <waldio.webdesign@gmail.com>
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'config:dump-reference', description: 'Dump the default configuration for an extension')]
|
||||
class ConfigDumpReferenceCommand extends AbstractConfigCommand
|
||||
{
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('name', InputArgument::OPTIONAL, 'The Bundle name or the extension alias'),
|
||||
new InputArgument('path', InputArgument::OPTIONAL, 'The configuration option path'),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'yaml'),
|
||||
])
|
||||
->setHelp(<<<EOF
|
||||
The <info>%command.name%</info> command dumps the default configuration for an
|
||||
extension/bundle.
|
||||
|
||||
Either the extension alias or bundle name can be used:
|
||||
|
||||
<info>php %command.full_name% framework</info>
|
||||
<info>php %command.full_name% FrameworkBundle</info>
|
||||
|
||||
The <info>--format</info> option specifies the format of the command output:
|
||||
|
||||
<info>php %command.full_name% FrameworkBundle --format=json</info>
|
||||
|
||||
For dumping a specific option, add its path as second argument (only available for the yaml format):
|
||||
|
||||
<info>php %command.full_name% framework http_client.default_options</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
if (null === $name = $input->getArgument('name')) {
|
||||
$this->listBundles($errorIo);
|
||||
$this->listNonBundleExtensions($errorIo);
|
||||
|
||||
$errorIo->comment([
|
||||
'Provide the name of a bundle as the first argument of this command to dump its default configuration. (e.g. <comment>config:dump-reference FrameworkBundle</comment>)',
|
||||
'For dumping a specific option, add its path as the second argument of this command. (e.g. <comment>config:dump-reference FrameworkBundle http_client.default_options</comment> to dump the <comment>framework.http_client.default_options</comment> configuration)',
|
||||
]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$extension = $this->findExtension($name);
|
||||
|
||||
if ($extension instanceof ConfigurationInterface) {
|
||||
$configuration = $extension;
|
||||
} else {
|
||||
$configuration = $extension->getConfiguration([], $this->getContainerBuilder($this->getApplication()->getKernel()));
|
||||
}
|
||||
|
||||
$this->validateConfiguration($extension, $configuration);
|
||||
|
||||
$format = $input->getOption('format');
|
||||
|
||||
if ('yaml' === $format && !class_exists(Yaml::class)) {
|
||||
$errorIo->error('Setting the "format" option to "yaml" requires the Symfony Yaml component. Try running "composer install symfony/yaml" or use "--format=xml" instead.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$path = $input->getArgument('path');
|
||||
|
||||
if (null !== $path && 'yaml' !== $format) {
|
||||
$errorIo->error('The "path" option is only available for the "yaml" format.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($name === $extension->getAlias()) {
|
||||
$message = \sprintf('Default configuration for extension with alias: "%s"', $name);
|
||||
} else {
|
||||
$message = \sprintf('Default configuration for "%s"', $name);
|
||||
}
|
||||
|
||||
if (null !== $path) {
|
||||
$message .= \sprintf(' at path "%s"', $path);
|
||||
}
|
||||
|
||||
if ($docUrl = $this->getExtensionDocUrl($extension)) {
|
||||
$message .= \sprintf(' (see %s)', $docUrl);
|
||||
}
|
||||
|
||||
switch ($format) {
|
||||
case 'yaml':
|
||||
$io->writeln(\sprintf('# %s', $message));
|
||||
$dumper = new YamlReferenceDumper();
|
||||
break;
|
||||
case 'xml':
|
||||
$io->writeln(\sprintf('<!-- %s -->', $message));
|
||||
$dumper = new XmlReferenceDumper();
|
||||
break;
|
||||
default:
|
||||
$io->writeln($message);
|
||||
throw new InvalidArgumentException(\sprintf('Supported formats are "%s".', implode('", "', $this->getAvailableFormatOptions())));
|
||||
}
|
||||
|
||||
$io->writeln(null === $path ? $dumper->dump($configuration, $extension->getNamespace()) : $dumper->dumpAtPath($configuration, $path));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('name')) {
|
||||
$suggestions->suggestValues($this->getAvailableExtensions());
|
||||
$suggestions->suggestValues($this->getAvailableBundles());
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues($this->getAvailableFormatOptions());
|
||||
}
|
||||
}
|
||||
|
||||
private function getAvailableExtensions(): array
|
||||
{
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
$extensions = [];
|
||||
foreach ($this->getContainerBuilder($kernel)->getExtensions() as $alias => $extension) {
|
||||
$extensions[] = $alias;
|
||||
}
|
||||
|
||||
return $extensions;
|
||||
}
|
||||
|
||||
private function getAvailableBundles(): array
|
||||
{
|
||||
$bundles = [];
|
||||
|
||||
foreach ($this->getApplication()->getKernel()->getBundles() as $bundle) {
|
||||
$bundles[] = $bundle->getName();
|
||||
}
|
||||
|
||||
return $bundles;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function getAvailableFormatOptions(): array
|
||||
{
|
||||
return ['yaml', 'xml'];
|
||||
}
|
||||
|
||||
private function getExtensionDocUrl(ConfigurationInterface|ConfigurationExtensionInterface $extension): ?string
|
||||
{
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$container = $this->getContainerBuilder($kernel);
|
||||
|
||||
$configuration = $extension instanceof ConfigurationInterface ? $extension : $extension->getConfiguration($container->getExtensionConfig($extension->getAlias()), $container);
|
||||
|
||||
return $configuration
|
||||
->getConfigTreeBuilder()
|
||||
->getRootNode()
|
||||
->getNode(true)
|
||||
->getAttribute('docUrl');
|
||||
}
|
||||
}
|
||||
376
vendor/symfony/framework-bundle/Command/ContainerDebugCommand.php
vendored
Normal file
376
vendor/symfony/framework-bundle/Command/ContainerDebugCommand.php
vendored
Normal file
@@ -0,0 +1,376 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
|
||||
/**
|
||||
* A console command for retrieving information about services.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@thatsquality.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
#[AsCommand(name: 'debug:container', description: 'Display current services for an application')]
|
||||
class ContainerDebugCommand extends Command
|
||||
{
|
||||
use BuildDebugContainerTrait;
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('name', InputArgument::OPTIONAL, 'A service name (foo)'),
|
||||
new InputOption('show-arguments', null, InputOption::VALUE_NONE, 'Show arguments in services'),
|
||||
new InputOption('show-hidden', null, InputOption::VALUE_NONE, 'Show hidden (internal) services'),
|
||||
new InputOption('tag', null, InputOption::VALUE_REQUIRED, 'Show all services with a specific tag'),
|
||||
new InputOption('tags', null, InputOption::VALUE_NONE, 'Display tagged services for an application'),
|
||||
new InputOption('parameter', null, InputOption::VALUE_REQUIRED, 'Display a specific parameter for an application'),
|
||||
new InputOption('parameters', null, InputOption::VALUE_NONE, 'Display parameters for an application'),
|
||||
new InputOption('types', null, InputOption::VALUE_NONE, 'Display types (classes/interfaces) available in the container'),
|
||||
new InputOption('env-var', null, InputOption::VALUE_REQUIRED, 'Display a specific environment variable used in the container'),
|
||||
new InputOption('env-vars', null, InputOption::VALUE_NONE, 'Display environment variables used in the container'),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'txt'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
|
||||
new InputOption('deprecations', null, InputOption::VALUE_NONE, 'Display deprecations generated when compiling and warming up the container'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command displays all configured <comment>public</comment> services:
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
To see deprecations generated during container compilation and cache warmup, use the <info>--deprecations</info> option:
|
||||
|
||||
<info>php %command.full_name% --deprecations</info>
|
||||
|
||||
To get specific information about a service, specify its name:
|
||||
|
||||
<info>php %command.full_name% validator</info>
|
||||
|
||||
To get specific information about a service including all its arguments, use the <info>--show-arguments</info> flag:
|
||||
|
||||
<info>php %command.full_name% validator --show-arguments</info>
|
||||
|
||||
To see available types that can be used for autowiring, use the <info>--types</info> flag:
|
||||
|
||||
<info>php %command.full_name% --types</info>
|
||||
|
||||
To see environment variables used by the container, use the <info>--env-vars</info> flag:
|
||||
|
||||
<info>php %command.full_name% --env-vars</info>
|
||||
|
||||
Display a specific environment variable by specifying its name with the <info>--env-var</info> option:
|
||||
|
||||
<info>php %command.full_name% --env-var=APP_ENV</info>
|
||||
|
||||
Use the --tags option to display tagged <comment>public</comment> services grouped by tag:
|
||||
|
||||
<info>php %command.full_name% --tags</info>
|
||||
|
||||
Find all services with a specific tag by specifying the tag name with the <info>--tag</info> option:
|
||||
|
||||
<info>php %command.full_name% --tag=form.type</info>
|
||||
|
||||
Use the <info>--parameters</info> option to display all parameters:
|
||||
|
||||
<info>php %command.full_name% --parameters</info>
|
||||
|
||||
Display a specific parameter by specifying its name with the <info>--parameter</info> option:
|
||||
|
||||
<info>php %command.full_name% --parameter=kernel.debug</info>
|
||||
|
||||
By default, internal services are hidden. You can display them
|
||||
using the <info>--show-hidden</info> flag:
|
||||
|
||||
<info>php %command.full_name% --show-hidden</info>
|
||||
|
||||
The <info>--format</info> option specifies the format of the command output:
|
||||
|
||||
<info>php %command.full_name% --format=json</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
$this->validateInput($input);
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$object = $this->getContainerBuilder($kernel);
|
||||
|
||||
if ($input->getOption('env-vars')) {
|
||||
$options = ['env-vars' => true];
|
||||
} elseif ($envVar = $input->getOption('env-var')) {
|
||||
$options = ['env-vars' => true, 'name' => $envVar];
|
||||
} elseif ($input->getOption('types')) {
|
||||
$options = [];
|
||||
$options['filter'] = $this->filterToServiceTypes(...);
|
||||
} elseif ($input->getOption('parameters')) {
|
||||
$parameters = [];
|
||||
$parameterBag = $object->getParameterBag();
|
||||
foreach ($parameterBag->all() as $k => $v) {
|
||||
$parameters[$k] = $object->resolveEnvPlaceholders($v);
|
||||
}
|
||||
$object = new ParameterBag($parameters);
|
||||
if ($parameterBag instanceof ParameterBag) {
|
||||
foreach ($parameterBag->allDeprecated() as $k => $deprecation) {
|
||||
$object->deprecate($k, ...$deprecation);
|
||||
}
|
||||
}
|
||||
$options = [];
|
||||
} elseif ($parameter = $input->getOption('parameter')) {
|
||||
$options = ['parameter' => $parameter];
|
||||
} elseif ($input->getOption('tags')) {
|
||||
$options = ['group_by' => 'tags'];
|
||||
} elseif ($tag = $input->getOption('tag')) {
|
||||
$tag = $this->findProperTagName($input, $errorIo, $object, $tag);
|
||||
$options = ['tag' => $tag];
|
||||
} elseif ($name = $input->getArgument('name')) {
|
||||
if ($input->getOption('show-arguments')) {
|
||||
$errorIo->warning('The "--show-arguments" option is deprecated.');
|
||||
}
|
||||
|
||||
$name = $this->findProperServiceName($input, $errorIo, $object, $name, $input->getOption('show-hidden'));
|
||||
$options = ['id' => $name];
|
||||
} elseif ($input->getOption('deprecations')) {
|
||||
$options = ['deprecations' => true];
|
||||
} else {
|
||||
$options = [];
|
||||
}
|
||||
|
||||
$helper = new DescriptorHelper();
|
||||
$options['format'] = $input->getOption('format');
|
||||
$options['show_hidden'] = $input->getOption('show-hidden');
|
||||
$options['raw_text'] = $input->getOption('raw');
|
||||
$options['output'] = $io;
|
||||
$options['is_debug'] = $kernel->isDebug();
|
||||
|
||||
try {
|
||||
$helper->describe($io, $object, $options);
|
||||
|
||||
if ('txt' === $options['format'] && isset($options['id'])) {
|
||||
if ($object->hasDefinition($options['id'])) {
|
||||
$definition = $object->getDefinition($options['id']);
|
||||
if ($definition->isDeprecated()) {
|
||||
$errorIo->warning($definition->getDeprecation($options['id'])['message'] ?? \sprintf('The "%s" service is deprecated.', $options['id']));
|
||||
}
|
||||
}
|
||||
if ($object->hasAlias($options['id'])) {
|
||||
$alias = $object->getAlias($options['id']);
|
||||
if ($alias->isDeprecated()) {
|
||||
$errorIo->warning($alias->getDeprecation($options['id'])['message'] ?? \sprintf('The "%s" alias is deprecated.', $options['id']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['id']) && isset($kernel->getContainer()->getRemovedIds()[$options['id']])) {
|
||||
$errorIo->note(\sprintf('The "%s" service or alias has been removed or inlined when the container was compiled.', $options['id']));
|
||||
}
|
||||
} catch (ServiceNotFoundException $e) {
|
||||
if ('' !== $e->getId() && '@' === $e->getId()[0]) {
|
||||
throw new ServiceNotFoundException($e->getId(), $e->getSourceId(), null, [substr($e->getId(), 1)]);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (!$input->getArgument('name') && !$input->getOption('tag') && !$input->getOption('parameter') && !$input->getOption('env-vars') && !$input->getOption('env-var') && $input->isInteractive()) {
|
||||
if ($input->getOption('tags')) {
|
||||
$errorIo->comment('To search for a specific tag, re-run this command with a search term. (e.g. <comment>debug:container --tag=form.type</comment>)');
|
||||
} elseif ($input->getOption('parameters')) {
|
||||
$errorIo->comment('To search for a specific parameter, re-run this command with a search term. (e.g. <comment>debug:container --parameter=kernel.debug</comment>)');
|
||||
} elseif (!$input->getOption('deprecations')) {
|
||||
$errorIo->comment('To search for a specific service, re-run this command with a search term. (e.g. <comment>debug:container log</comment>)');
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues($this->getAvailableFormatOptions());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$object = $this->getContainerBuilder($kernel);
|
||||
|
||||
if ($input->mustSuggestArgumentValuesFor('name')
|
||||
&& !$input->getOption('tag') && !$input->getOption('tags')
|
||||
&& !$input->getOption('parameter') && !$input->getOption('parameters')
|
||||
&& !$input->getOption('env-var') && !$input->getOption('env-vars')
|
||||
&& !$input->getOption('types') && !$input->getOption('deprecations')
|
||||
) {
|
||||
$suggestions->suggestValues($this->findServiceIdsContaining(
|
||||
$object,
|
||||
$input->getCompletionValue(),
|
||||
(bool) $input->getOption('show-hidden')
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('tag')) {
|
||||
$suggestions->suggestValues($object->findTags());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('parameter')) {
|
||||
$suggestions->suggestValues(array_keys($object->getParameterBag()->all()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates input arguments and options.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
protected function validateInput(InputInterface $input): void
|
||||
{
|
||||
$options = ['tags', 'tag', 'parameters', 'parameter'];
|
||||
|
||||
$optionsCount = 0;
|
||||
foreach ($options as $option) {
|
||||
if ($input->getOption($option)) {
|
||||
++$optionsCount;
|
||||
}
|
||||
}
|
||||
|
||||
$name = $input->getArgument('name');
|
||||
if ((null !== $name) && ($optionsCount > 0)) {
|
||||
throw new InvalidArgumentException('The options tags, tag, parameters & parameter cannot be combined with the service name argument.');
|
||||
} elseif ((null === $name) && $optionsCount > 1) {
|
||||
throw new InvalidArgumentException('The options tags, tag, parameters & parameter cannot be combined together.');
|
||||
}
|
||||
}
|
||||
|
||||
private function findProperServiceName(InputInterface $input, SymfonyStyle $io, ContainerBuilder $container, string $name, bool $showHidden): string
|
||||
{
|
||||
$name = ltrim($name, '\\');
|
||||
|
||||
if ($container->has($name) || !$input->isInteractive()) {
|
||||
return $name;
|
||||
}
|
||||
|
||||
$matchingServices = $this->findServiceIdsContaining($container, $name, $showHidden);
|
||||
if (!$matchingServices) {
|
||||
throw new InvalidArgumentException(\sprintf('No services found that match "%s".', $name));
|
||||
}
|
||||
|
||||
if (1 === \count($matchingServices)) {
|
||||
return $matchingServices[0];
|
||||
}
|
||||
|
||||
natsort($matchingServices);
|
||||
|
||||
return $io->choice('Select one of the following services to display its information', array_values($matchingServices));
|
||||
}
|
||||
|
||||
private function findProperTagName(InputInterface $input, SymfonyStyle $io, ContainerBuilder $container, string $tagName): string
|
||||
{
|
||||
if (\in_array($tagName, $container->findTags(), true) || !$input->isInteractive()) {
|
||||
return $tagName;
|
||||
}
|
||||
|
||||
$matchingTags = $this->findTagsContaining($container, $tagName);
|
||||
if (!$matchingTags) {
|
||||
throw new InvalidArgumentException(\sprintf('No tags found that match "%s".', $tagName));
|
||||
}
|
||||
|
||||
if (1 === \count($matchingTags)) {
|
||||
return $matchingTags[0];
|
||||
}
|
||||
|
||||
natsort($matchingTags);
|
||||
|
||||
return $io->choice('Select one of the following tags to display its information', array_values($matchingTags));
|
||||
}
|
||||
|
||||
private function findServiceIdsContaining(ContainerBuilder $container, string $name, bool $showHidden): array
|
||||
{
|
||||
$serviceIds = $container->getServiceIds();
|
||||
$foundServiceIds = $foundServiceIdsIgnoringBackslashes = [];
|
||||
foreach ($serviceIds as $serviceId) {
|
||||
if (!$showHidden && str_starts_with($serviceId, '.')) {
|
||||
continue;
|
||||
}
|
||||
if (!$showHidden && $container->hasDefinition($serviceId) && $container->getDefinition($serviceId)->hasTag('container.excluded')) {
|
||||
continue;
|
||||
}
|
||||
if (false !== stripos(str_replace('\\', '', $serviceId), $name)) {
|
||||
$foundServiceIdsIgnoringBackslashes[] = $serviceId;
|
||||
}
|
||||
if ('' === $name || false !== stripos($serviceId, $name)) {
|
||||
$foundServiceIds[] = $serviceId;
|
||||
}
|
||||
}
|
||||
|
||||
return $foundServiceIds ?: $foundServiceIdsIgnoringBackslashes;
|
||||
}
|
||||
|
||||
private function findTagsContaining(ContainerBuilder $container, string $tagName): array
|
||||
{
|
||||
$tags = $container->findTags();
|
||||
$foundTags = [];
|
||||
foreach ($tags as $tag) {
|
||||
if (str_contains($tag, $tagName)) {
|
||||
$foundTags[] = $tag;
|
||||
}
|
||||
}
|
||||
|
||||
return $foundTags;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function filterToServiceTypes(string $serviceId): bool
|
||||
{
|
||||
// filter out things that could not be valid class names
|
||||
if (!preg_match('/(?(DEFINE)(?<V>[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*+))^(?&V)(?:\\\\(?&V))*+(?: \$(?&V))?$/', $serviceId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the id has a \, assume it is a class
|
||||
if (str_contains($serviceId, '\\')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return class_exists($serviceId) || interface_exists($serviceId, false);
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function getAvailableFormatOptions(): array
|
||||
{
|
||||
return (new DescriptorHelper())->getFormats();
|
||||
}
|
||||
}
|
||||
127
vendor/symfony/framework-bundle/Command/ContainerLintCommand.php
vendored
Normal file
127
vendor/symfony/framework-bundle/Command/ContainerLintCommand.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Config\ConfigCache;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CheckAliasValidityPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveFactoryClassPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
|
||||
#[AsCommand(name: 'lint:container', description: 'Ensure that arguments injected into services match type declarations')]
|
||||
final class ContainerLintCommand extends Command
|
||||
{
|
||||
private ContainerBuilder $container;
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setHelp('This command parses service definitions and ensures that injected values match the type declarations of each services\' class.')
|
||||
->addOption('resolve-env-vars', null, InputOption::VALUE_NONE, 'Resolve environment variables and fail if one is missing.')
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
$resolveEnvVars = $input->getOption('resolve-env-vars');
|
||||
|
||||
try {
|
||||
$container = $this->getContainerBuilder($resolveEnvVars);
|
||||
} catch (RuntimeException $e) {
|
||||
$errorIo->error($e->getMessage());
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
$container->setParameter('container.build_time', time());
|
||||
|
||||
try {
|
||||
$container->compile($resolveEnvVars);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
$errorIo->error($e->getMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$io->success('The container was linted successfully: all services are injected with values that are compatible with their type declarations.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function getContainerBuilder(bool $resolveEnvVars): ContainerBuilder
|
||||
{
|
||||
if (isset($this->container)) {
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
$kernelContainer = $kernel->getContainer();
|
||||
|
||||
if (!$kernel->isDebug() || !$kernelContainer->getParameter('debug.container.dump') || !(new ConfigCache($kernelContainer->getParameter('debug.container.dump'), true))->isFresh()) {
|
||||
if (!$kernel instanceof Kernel) {
|
||||
throw new RuntimeException(\sprintf('This command does not support the application kernel: "%s" does not extend "%s".', get_debug_type($kernel), Kernel::class));
|
||||
}
|
||||
|
||||
$buildContainer = \Closure::bind(function (): ContainerBuilder {
|
||||
$this->initializeBundles();
|
||||
|
||||
return $this->buildContainer();
|
||||
}, $kernel, $kernel::class);
|
||||
$container = $buildContainer();
|
||||
} else {
|
||||
if (!$kernelContainer instanceof Container) {
|
||||
throw new RuntimeException(\sprintf('This command does not support the application container: "%s" does not extend "%s".', get_debug_type($kernelContainer), Container::class));
|
||||
}
|
||||
|
||||
(new XmlFileLoader($container = new ContainerBuilder($parameterBag = new EnvPlaceholderParameterBag()), new FileLocator()))->load($kernelContainer->getParameter('debug.container.dump'));
|
||||
|
||||
if ($resolveEnvVars) {
|
||||
$container->getCompilerPassConfig()->setOptimizationPasses([new ResolveParameterPlaceHoldersPass(), new ResolveFactoryClassPass()]);
|
||||
} else {
|
||||
$refl = new \ReflectionProperty($parameterBag, 'resolved');
|
||||
$refl->setValue($parameterBag, true);
|
||||
|
||||
$container->getCompilerPassConfig()->setOptimizationPasses([new ResolveFactoryClassPass()]);
|
||||
}
|
||||
|
||||
$container->getCompilerPassConfig()->setBeforeOptimizationPasses([]);
|
||||
$container->getCompilerPassConfig()->setBeforeRemovingPasses([]);
|
||||
}
|
||||
|
||||
$container->setParameter('container.build_hash', 'lint_container');
|
||||
$container->setParameter('container.build_id', 'lint_container');
|
||||
$container->setParameter('container.runtime_mode', 'web=0');
|
||||
|
||||
$container->addCompilerPass(new CheckAliasValidityPass(), PassConfig::TYPE_BEFORE_REMOVING, -100);
|
||||
$container->addCompilerPass(new CheckTypeDeclarationsPass(true), PassConfig::TYPE_AFTER_REMOVING, -100);
|
||||
|
||||
return $this->container = $container;
|
||||
}
|
||||
}
|
||||
199
vendor/symfony/framework-bundle/Command/DebugAutowiringCommand.php
vendored
Normal file
199
vendor/symfony/framework-bundle/Command/DebugAutowiringCommand.php
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\Descriptor;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\Attribute\Target;
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
|
||||
|
||||
/**
|
||||
* A console command for autowiring information.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
#[AsCommand(name: 'debug:autowiring', description: 'List classes/interfaces you can use for autowiring')]
|
||||
class DebugAutowiringCommand extends ContainerDebugCommand
|
||||
{
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
private ?FileLinkFormatter $fileLinkFormatter = null,
|
||||
) {
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('search', InputArgument::OPTIONAL, 'A search filter'),
|
||||
new InputOption('all', null, InputOption::VALUE_NONE, 'Show also services that are not aliased'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command displays the classes and interfaces that
|
||||
you can use as type-hints for autowiring:
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
You can also pass a search term to filter the list:
|
||||
|
||||
<info>php %command.full_name% log</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
$container = $this->getContainerBuilder($this->getApplication()->getKernel());
|
||||
$serviceIds = $container->getServiceIds();
|
||||
$serviceIds = array_filter($serviceIds, $this->filterToServiceTypes(...));
|
||||
|
||||
if ($search = $input->getArgument('search')) {
|
||||
$searchNormalized = preg_replace('/[^a-zA-Z0-9\x7f-\xff $]++/', '', $search);
|
||||
|
||||
$serviceIds = array_filter($serviceIds, fn ($serviceId) => false !== stripos(str_replace('\\', '', $serviceId), $searchNormalized) && !str_starts_with($serviceId, '.'));
|
||||
|
||||
if (!$serviceIds) {
|
||||
$errorIo->error(\sprintf('No autowirable classes or interfaces found matching "%s"', $search));
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
$reverseAliases = [];
|
||||
|
||||
foreach ($container->getAliases() as $id => $alias) {
|
||||
if ('.' === ($id[0] ?? null)) {
|
||||
$reverseAliases[(string) $alias][] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
uasort($serviceIds, 'strnatcmp');
|
||||
|
||||
$io->title('Autowirable Types');
|
||||
$io->text('The following classes & interfaces can be used as type-hints when autowiring:');
|
||||
if ($search) {
|
||||
$io->text(\sprintf('(only showing classes/interfaces matching <comment>%s</comment>)', $search));
|
||||
}
|
||||
$hasAlias = [];
|
||||
$all = $input->getOption('all');
|
||||
$previousId = '-';
|
||||
$serviceIdsNb = 0;
|
||||
foreach ($serviceIds as $serviceId) {
|
||||
if ($container->hasDefinition($serviceId) && $container->getDefinition($serviceId)->hasTag('container.excluded')) {
|
||||
continue;
|
||||
}
|
||||
$text = [];
|
||||
$resolvedServiceId = $serviceId;
|
||||
if (!str_starts_with($serviceId, $previousId.' $')) {
|
||||
$text[] = '';
|
||||
$previousId = preg_replace('/ \$.*/', '', $serviceId);
|
||||
if ('' !== $description = Descriptor::getClassDescription($previousId, $resolvedServiceId)) {
|
||||
if (isset($hasAlias[$previousId])) {
|
||||
continue;
|
||||
}
|
||||
$text[] = $description;
|
||||
}
|
||||
}
|
||||
|
||||
$serviceLine = \sprintf('<fg=yellow>%s</>', $serviceId);
|
||||
if ('' !== $fileLink = $this->getFileLink($previousId)) {
|
||||
$serviceLine = substr($serviceId, \strlen($previousId));
|
||||
$serviceLine = \sprintf('<fg=yellow;href=%s>%s</>', $fileLink, $previousId).('' !== $serviceLine ? \sprintf('<fg=yellow>%s</>', $serviceLine) : '');
|
||||
}
|
||||
|
||||
if ($container->hasAlias($serviceId)) {
|
||||
$hasAlias[$serviceId] = true;
|
||||
$serviceAlias = $container->getAlias($serviceId);
|
||||
$alias = (string) $serviceAlias;
|
||||
|
||||
$target = null;
|
||||
foreach ($reverseAliases[(string) $serviceAlias] ?? [] as $id) {
|
||||
if (!str_starts_with($id, '.'.$previousId.' $')) {
|
||||
continue;
|
||||
}
|
||||
$target = substr($id, \strlen($previousId) + 3);
|
||||
|
||||
if ($previousId.' $'.(new Target($target))->getParsedName() === $serviceId) {
|
||||
$serviceLine .= ' - <fg=magenta>target:</><fg=cyan>'.$target.'</>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($container->hasDefinition($serviceAlias) && $decorated = $container->getDefinition($serviceAlias)->getTag('container.decorator')) {
|
||||
$alias = $decorated[0]['id'];
|
||||
}
|
||||
|
||||
if ($alias !== $target) {
|
||||
$serviceLine .= ' - <fg=magenta>alias:</><fg=cyan>'.$alias.'</>';
|
||||
}
|
||||
|
||||
if ($serviceAlias->isDeprecated()) {
|
||||
$serviceLine .= ' - <fg=magenta>deprecated</>';
|
||||
}
|
||||
} elseif (!$all) {
|
||||
++$serviceIdsNb;
|
||||
continue;
|
||||
} elseif ($container->getDefinition($serviceId)->isDeprecated()) {
|
||||
$serviceLine .= ' - <fg=magenta>deprecated</>';
|
||||
}
|
||||
$text[] = $serviceLine;
|
||||
$io->text($text);
|
||||
}
|
||||
|
||||
$io->newLine();
|
||||
|
||||
if (0 < $serviceIdsNb) {
|
||||
$io->text(\sprintf('%s more concrete service%s would be displayed when adding the "--all" option.', $serviceIdsNb, $serviceIdsNb > 1 ? 's' : ''));
|
||||
}
|
||||
if ($all) {
|
||||
$io->text('Pro-tip: use interfaces in your type-hints instead of classes to benefit from the dependency inversion principle.');
|
||||
}
|
||||
|
||||
$io->newLine();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function getFileLink(string $class): string
|
||||
{
|
||||
if (null === $this->fileLinkFormatter
|
||||
|| (null === $r = $this->getContainerBuilder($this->getApplication()->getKernel())->getReflectionClass($class, false))) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return (string) $this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine());
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('search')) {
|
||||
$container = $this->getContainerBuilder($this->getApplication()->getKernel());
|
||||
|
||||
$suggestions->suggestValues(array_filter($container->getServiceIds(), $this->filterToServiceTypes(...)));
|
||||
}
|
||||
}
|
||||
}
|
||||
165
vendor/symfony/framework-bundle/Command/EventDispatcherDebugCommand.php
vendored
Normal file
165
vendor/symfony/framework-bundle/Command/EventDispatcherDebugCommand.php
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Contracts\Service\ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* A console command for retrieving information about event dispatcher.
|
||||
*
|
||||
* @author Matthieu Auger <mail@matthieuauger.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'debug:event-dispatcher', description: 'Display configured listeners for an application')]
|
||||
class EventDispatcherDebugCommand extends Command
|
||||
{
|
||||
private const DEFAULT_DISPATCHER = 'event_dispatcher';
|
||||
|
||||
public function __construct(
|
||||
private ContainerInterface $dispatchers,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('event', InputArgument::OPTIONAL, 'An event name or a part of the event name'),
|
||||
new InputOption('dispatcher', null, InputOption::VALUE_REQUIRED, 'To view events of a specific event dispatcher', self::DEFAULT_DISPATCHER),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'txt'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command displays all configured listeners:
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
To get specific listeners for an event, specify its name:
|
||||
|
||||
<info>php %command.full_name% kernel.request</info>
|
||||
|
||||
The <info>--format</info> option specifies the format of the command output:
|
||||
|
||||
<info>php %command.full_name% --format=json</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$options = [];
|
||||
$dispatcherServiceName = $input->getOption('dispatcher');
|
||||
if (!$this->dispatchers->has($dispatcherServiceName)) {
|
||||
$io->getErrorStyle()->error(\sprintf('Event dispatcher "%s" is not available.', $dispatcherServiceName));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$dispatcher = $this->dispatchers->get($dispatcherServiceName);
|
||||
|
||||
if ($event = $input->getArgument('event')) {
|
||||
if ($dispatcher->hasListeners($event)) {
|
||||
$options = ['event' => $event];
|
||||
} else {
|
||||
// if there is no direct match, try find partial matches
|
||||
$events = $this->searchForEvent($dispatcher, $event);
|
||||
if (0 === \count($events)) {
|
||||
$io->getErrorStyle()->warning(\sprintf('The event "%s" does not have any registered listeners.', $event));
|
||||
|
||||
return 0;
|
||||
} elseif (1 === \count($events)) {
|
||||
$options = ['event' => $events[array_key_first($events)]];
|
||||
} else {
|
||||
$options = ['events' => $events];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$helper = new DescriptorHelper();
|
||||
|
||||
if (self::DEFAULT_DISPATCHER !== $dispatcherServiceName) {
|
||||
$options['dispatcher_service_name'] = $dispatcherServiceName;
|
||||
}
|
||||
|
||||
$options['format'] = $input->getOption('format');
|
||||
$options['raw_text'] = $input->getOption('raw');
|
||||
$options['output'] = $io;
|
||||
$helper->describe($io, $dispatcher, $options);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('event')) {
|
||||
$dispatcherServiceName = $input->getOption('dispatcher');
|
||||
if ($this->dispatchers->has($dispatcherServiceName)) {
|
||||
$dispatcher = $this->dispatchers->get($dispatcherServiceName);
|
||||
$suggestions->suggestValues(array_keys($dispatcher->getListeners()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('dispatcher')) {
|
||||
if ($this->dispatchers instanceof ServiceProviderInterface) {
|
||||
$suggestions->suggestValues(array_keys($this->dispatchers->getProvidedServices()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues($this->getAvailableFormatOptions());
|
||||
}
|
||||
}
|
||||
|
||||
private function searchForEvent(EventDispatcherInterface $dispatcher, string $needle): array
|
||||
{
|
||||
$output = [];
|
||||
$lcNeedle = strtolower($needle);
|
||||
$allEvents = array_keys($dispatcher->getListeners());
|
||||
foreach ($allEvents as $event) {
|
||||
if (str_contains(strtolower($event), $lcNeedle)) {
|
||||
$output[] = $event;
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function getAvailableFormatOptions(): array
|
||||
{
|
||||
return (new DescriptorHelper())->getFormats();
|
||||
}
|
||||
}
|
||||
179
vendor/symfony/framework-bundle/Command/RouterDebugCommand.php
vendored
Normal file
179
vendor/symfony/framework-bundle/Command/RouterDebugCommand.php
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Helper\DescriptorHelper;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
|
||||
/**
|
||||
* A console command for retrieving information about routes.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'debug:router', description: 'Display current routes for an application')]
|
||||
class RouterDebugCommand extends Command
|
||||
{
|
||||
use BuildDebugContainerTrait;
|
||||
|
||||
public function __construct(
|
||||
private RouterInterface $router,
|
||||
private ?FileLinkFormatter $fileLinkFormatter = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('name', InputArgument::OPTIONAL, 'A route name'),
|
||||
new InputOption('show-controllers', null, InputOption::VALUE_NONE, 'Show assigned controllers in overview'),
|
||||
new InputOption('show-aliases', null, InputOption::VALUE_NONE, 'Show aliases in overview'),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, \sprintf('The output format ("%s")', implode('", "', $this->getAvailableFormatOptions())), 'txt'),
|
||||
new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw route(s)'),
|
||||
new InputOption('method', null, InputOption::VALUE_REQUIRED, 'Filter by HTTP method', '', ['GET', 'POST', 'PUT', 'DELETE', 'PATCH']),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> displays the configured routes:
|
||||
|
||||
<info>php %command.full_name%</info>
|
||||
|
||||
The <info>--format</info> option specifies the format of the command output:
|
||||
|
||||
<info>php %command.full_name% --format=json</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException When route does not exist
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$name = $input->getArgument('name');
|
||||
$method = strtoupper($input->getOption('method'));
|
||||
$helper = new DescriptorHelper($this->fileLinkFormatter);
|
||||
$routes = $this->router->getRouteCollection();
|
||||
$container = null;
|
||||
if ($this->fileLinkFormatter) {
|
||||
$container = fn () => $this->getContainerBuilder($this->getApplication()->getKernel());
|
||||
}
|
||||
|
||||
if ($name) {
|
||||
$route = $routes->get($name);
|
||||
$matchingRoutes = $this->findRouteNameContaining($name, $routes, $method);
|
||||
|
||||
if (!$input->isInteractive() && !$route && \count($matchingRoutes) > 1) {
|
||||
$helper->describe($io, $this->findRouteContaining($name, $routes), [
|
||||
'format' => $input->getOption('format'),
|
||||
'raw_text' => $input->getOption('raw'),
|
||||
'show_controllers' => $input->getOption('show-controllers'),
|
||||
'show_aliases' => $input->getOption('show-aliases'),
|
||||
'output' => $io,
|
||||
'method' => $method,
|
||||
]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!$route && $matchingRoutes) {
|
||||
$default = 1 === \count($matchingRoutes) ? $matchingRoutes[0] : null;
|
||||
$name = $io->choice('Select one of the matching routes', $matchingRoutes, $default);
|
||||
$route = $routes->get($name);
|
||||
}
|
||||
|
||||
if (!$route) {
|
||||
throw new InvalidArgumentException(\sprintf('The route "%s" does not exist.', $name));
|
||||
}
|
||||
|
||||
$helper->describe($io, $route, [
|
||||
'format' => $input->getOption('format'),
|
||||
'raw_text' => $input->getOption('raw'),
|
||||
'name' => $name,
|
||||
'output' => $io,
|
||||
'container' => $container,
|
||||
]);
|
||||
} else {
|
||||
$helper->describe($io, $routes, [
|
||||
'format' => $input->getOption('format'),
|
||||
'raw_text' => $input->getOption('raw'),
|
||||
'show_controllers' => $input->getOption('show-controllers'),
|
||||
'show_aliases' => $input->getOption('show-aliases'),
|
||||
'output' => $io,
|
||||
'container' => $container,
|
||||
'method' => $method,
|
||||
]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function findRouteNameContaining(string $name, RouteCollection $routes, string $method): array
|
||||
{
|
||||
$foundRoutesNames = [];
|
||||
foreach ($routes as $routeName => $route) {
|
||||
if (false !== stripos($routeName, $name) && (!$method || !$route->getMethods() || \in_array($method, $route->getMethods(), true))) {
|
||||
$foundRoutesNames[] = $routeName;
|
||||
}
|
||||
}
|
||||
|
||||
return $foundRoutesNames;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('name')) {
|
||||
$suggestions->suggestValues(array_keys($this->router->getRouteCollection()->all()));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues($this->getAvailableFormatOptions());
|
||||
}
|
||||
}
|
||||
|
||||
private function findRouteContaining(string $name, RouteCollection $routes): RouteCollection
|
||||
{
|
||||
$foundRoutes = new RouteCollection();
|
||||
foreach ($routes as $routeName => $route) {
|
||||
if (false !== stripos($routeName, $name)) {
|
||||
$foundRoutes->add($routeName, $route);
|
||||
}
|
||||
}
|
||||
|
||||
return $foundRoutes;
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
private function getAvailableFormatOptions(): array
|
||||
{
|
||||
return (new DescriptorHelper())->getFormats();
|
||||
}
|
||||
}
|
||||
117
vendor/symfony/framework-bundle/Command/RouterMatchCommand.php
vendored
Normal file
117
vendor/symfony/framework-bundle/Command/RouterMatchCommand.php
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
|
||||
use Symfony\Component\Routing\Matcher\TraceableUrlMatcher;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
|
||||
/**
|
||||
* A console command to test route matching.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'router:match', description: 'Help debug routes by simulating a path info match')]
|
||||
class RouterMatchCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @param iterable<mixed, ExpressionFunctionProviderInterface> $expressionLanguageProviders
|
||||
*/
|
||||
public function __construct(
|
||||
private RouterInterface $router,
|
||||
private iterable $expressionLanguageProviders = [],
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('path_info', InputArgument::REQUIRED, 'A path info'),
|
||||
new InputOption('method', null, InputOption::VALUE_REQUIRED, 'Set the HTTP method'),
|
||||
new InputOption('scheme', null, InputOption::VALUE_REQUIRED, 'Set the URI scheme (usually http or https)'),
|
||||
new InputOption('host', null, InputOption::VALUE_REQUIRED, 'Set the URI host'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> shows which routes match a given request and which don't and for what reason:
|
||||
|
||||
<info>php %command.full_name% /foo</info>
|
||||
|
||||
or
|
||||
|
||||
<info>php %command.full_name% /foo --method POST --scheme https --host symfony.com --verbose</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$context = $this->router->getContext();
|
||||
if (null !== $method = $input->getOption('method')) {
|
||||
$context->setMethod($method);
|
||||
}
|
||||
if (null !== $scheme = $input->getOption('scheme')) {
|
||||
$context->setScheme($scheme);
|
||||
}
|
||||
if (null !== $host = $input->getOption('host')) {
|
||||
$context->setHost($host);
|
||||
}
|
||||
|
||||
$matcher = new TraceableUrlMatcher($this->router->getRouteCollection(), $context);
|
||||
foreach ($this->expressionLanguageProviders as $provider) {
|
||||
$matcher->addExpressionLanguageProvider($provider);
|
||||
}
|
||||
|
||||
$traces = $matcher->getTraces($input->getArgument('path_info'));
|
||||
|
||||
$io->newLine();
|
||||
|
||||
$matches = false;
|
||||
foreach ($traces as $trace) {
|
||||
if (TraceableUrlMatcher::ROUTE_ALMOST_MATCHES == $trace['level']) {
|
||||
$io->text(\sprintf('Route <info>"%s"</> almost matches but %s', $trace['name'], lcfirst($trace['log'])));
|
||||
} elseif (TraceableUrlMatcher::ROUTE_MATCHES == $trace['level']) {
|
||||
$io->success(\sprintf('Route "%s" matches', $trace['name']));
|
||||
|
||||
$routerDebugCommand = $this->getApplication()->find('debug:router');
|
||||
$routerDebugCommand->run(new ArrayInput(['name' => $trace['name']]), $output);
|
||||
|
||||
$matches = true;
|
||||
} elseif ($input->getOption('verbose')) {
|
||||
$io->text(\sprintf('Route "%s" does not match: %s', $trace['name'], $trace['log']));
|
||||
}
|
||||
}
|
||||
|
||||
if (!$matches) {
|
||||
$io->error(\sprintf('None of the routes match the path "%s"', $input->getArgument('path_info')));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
104
vendor/symfony/framework-bundle/Command/SecretsDecryptToLocalCommand.php
vendored
Normal file
104
vendor/symfony/framework-bundle/Command/SecretsDecryptToLocalCommand.php
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
#[AsCommand(name: 'secrets:decrypt-to-local', description: 'Decrypt all secrets and stores them in the local vault')]
|
||||
final class SecretsDecryptToLocalCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private AbstractVault $vault,
|
||||
private ?AbstractVault $localVault = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('force', 'f', InputOption::VALUE_NONE, 'Force overriding of secrets that already exist in the local vault')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command decrypts all secrets and copies them in the local vault.
|
||||
|
||||
<info>%command.full_name%</info>
|
||||
|
||||
When the <info>--force</info> option is provided, secrets that already exist in the local vault are overridden.
|
||||
|
||||
<info>%command.full_name% --force</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
|
||||
if (null === $this->localVault) {
|
||||
$io->error('The local vault is disabled.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$secrets = $this->vault->list(true);
|
||||
|
||||
$io->comment(\sprintf('%d secret%s found in the vault.', \count($secrets), 1 !== \count($secrets) ? 's' : ''));
|
||||
|
||||
$skipped = 0;
|
||||
if (!$input->getOption('force')) {
|
||||
foreach ($this->localVault->list() as $k => $v) {
|
||||
if (isset($secrets[$k])) {
|
||||
++$skipped;
|
||||
unset($secrets[$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($skipped > 0) {
|
||||
$io->warning([
|
||||
\sprintf('%d secret%s already overridden in the local vault and will be skipped.', $skipped, 1 !== $skipped ? 's are' : ' is'),
|
||||
'Use the --force flag to override these.',
|
||||
]);
|
||||
}
|
||||
|
||||
$hadErrors = false;
|
||||
foreach ($secrets as $k => $v) {
|
||||
if (null === $v) {
|
||||
$io->error($this->vault->getLastMessage() ?? \sprintf('Secret "%s" has been skipped as there was an error reading it.', $k));
|
||||
$hadErrors = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->localVault->seal($k, $v);
|
||||
$io->note($this->localVault->getLastMessage());
|
||||
}
|
||||
|
||||
if ($hadErrors) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
73
vendor/symfony/framework-bundle/Command/SecretsEncryptFromLocalCommand.php
vendored
Normal file
73
vendor/symfony/framework-bundle/Command/SecretsEncryptFromLocalCommand.php
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
#[AsCommand(name: 'secrets:encrypt-from-local', description: 'Encrypt all local secrets to the vault')]
|
||||
final class SecretsEncryptFromLocalCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private AbstractVault $vault,
|
||||
private ?AbstractVault $localVault = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command encrypts all locally overridden secrets to the vault.
|
||||
|
||||
<info>%command.full_name%</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
|
||||
if (null === $this->localVault) {
|
||||
$io->error('The local vault is disabled.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
foreach ($this->vault->list(true) as $name => $value) {
|
||||
$localValue = $this->localVault->reveal($name);
|
||||
|
||||
if (null !== $localValue && $value !== $localValue) {
|
||||
$this->vault->seal($name, $localValue);
|
||||
} elseif (null !== $message = $this->localVault->getLastMessage()) {
|
||||
$io->error($message);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
120
vendor/symfony/framework-bundle/Command/SecretsGenerateKeysCommand.php
vendored
Normal file
120
vendor/symfony/framework-bundle/Command/SecretsGenerateKeysCommand.php
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
#[AsCommand(name: 'secrets:generate-keys', description: 'Generate new encryption keys')]
|
||||
final class SecretsGenerateKeysCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private AbstractVault $vault,
|
||||
private ?AbstractVault $localVault = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('local', 'l', InputOption::VALUE_NONE, 'Update the local vault.')
|
||||
->addOption('rotate', 'r', InputOption::VALUE_NONE, 'Re-encrypt existing secrets with the newly generated keys.')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command generates a new encryption key.
|
||||
|
||||
<info>%command.full_name%</info>
|
||||
|
||||
If encryption keys already exist, the command must be called with
|
||||
the <info>--rotate</info> option in order to override those keys and re-encrypt
|
||||
existing secrets.
|
||||
|
||||
<info>%command.full_name% --rotate</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
$vault = $input->getOption('local') ? $this->localVault : $this->vault;
|
||||
|
||||
if (null === $vault) {
|
||||
$io->error('The local vault is disabled.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!$input->getOption('rotate')) {
|
||||
if ($vault->generateKeys()) {
|
||||
$io->success($vault->getLastMessage());
|
||||
|
||||
if ($this->vault === $vault) {
|
||||
$io->caution('DO NOT COMMIT THE DECRYPTION KEY FOR THE PROD ENVIRONMENT⚠️');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$io->warning($vault->getLastMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$secrets = [];
|
||||
foreach ($vault->list(true) as $name => $value) {
|
||||
if (null === $value) {
|
||||
$io->error($vault->getLastMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$secrets[$name] = $value;
|
||||
}
|
||||
|
||||
if (!$vault->generateKeys(true)) {
|
||||
$io->warning($vault->getLastMessage());
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$io->success($vault->getLastMessage());
|
||||
|
||||
if ($secrets) {
|
||||
foreach ($secrets as $name => $value) {
|
||||
$vault->seal($name, $value);
|
||||
}
|
||||
|
||||
$io->comment('Existing secrets have been rotated to the new keys.');
|
||||
}
|
||||
|
||||
if ($this->vault === $vault) {
|
||||
$io->caution('DO NOT COMMIT THE DECRYPTION KEY FOR THE PROD ENVIRONMENT⚠️');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
101
vendor/symfony/framework-bundle/Command/SecretsListCommand.php
vendored
Normal file
101
vendor/symfony/framework-bundle/Command/SecretsListCommand.php
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Helper\Dumper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
#[AsCommand(name: 'secrets:list', description: 'List all secrets')]
|
||||
final class SecretsListCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private AbstractVault $vault,
|
||||
private ?AbstractVault $localVault = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addOption('reveal', 'r', InputOption::VALUE_NONE, 'Display decrypted values alongside names')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command list all stored secrets.
|
||||
|
||||
<info>%command.full_name%</info>
|
||||
|
||||
When the option <info>--reveal</info> is provided, the decrypted secrets are also displayed.
|
||||
|
||||
<info>%command.full_name% --reveal</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
|
||||
$io->comment('Use <info>"%env(<name>)%"</info> to reference a secret in a config file.');
|
||||
|
||||
if (!$reveal = $input->getOption('reveal')) {
|
||||
$io->comment(\sprintf('To reveal the secrets run <info>php %s %s --reveal</info>', $_SERVER['PHP_SELF'], $this->getName()));
|
||||
}
|
||||
|
||||
$secrets = $this->vault->list($reveal);
|
||||
$localSecrets = $this->localVault?->list($reveal);
|
||||
|
||||
$rows = [];
|
||||
|
||||
$dump = new Dumper($output);
|
||||
$dump = fn ($v) => null === $v ? '******' : $dump($v);
|
||||
|
||||
foreach ($secrets as $name => $value) {
|
||||
$rows[$name] = [$name, $dump($value)];
|
||||
}
|
||||
|
||||
if (null !== $message = $this->vault->getLastMessage()) {
|
||||
$io->comment($message);
|
||||
}
|
||||
|
||||
foreach ($localSecrets ?? [] as $name => $value) {
|
||||
if (isset($rows[$name])) {
|
||||
$rows[$name][] = $dump($value);
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $this->localVault && null !== $message = $this->localVault->getLastMessage()) {
|
||||
$io->comment($message);
|
||||
}
|
||||
|
||||
(new SymfonyStyle($input, $output))
|
||||
->table(['Secret', 'Value'] + (null !== $localSecrets ? [2 => 'Local Value'] : []), $rows);
|
||||
|
||||
$io->comment("Local values override secret values.\nUse <info>secrets:set --local</info> to define them.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
96
vendor/symfony/framework-bundle/Command/SecretsRemoveCommand.php
vendored
Normal file
96
vendor/symfony/framework-bundle/Command/SecretsRemoveCommand.php
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
#[AsCommand(name: 'secrets:remove', description: 'Remove a secret from the vault')]
|
||||
final class SecretsRemoveCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private AbstractVault $vault,
|
||||
private ?AbstractVault $localVault = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'The name of the secret')
|
||||
->addOption('local', 'l', InputOption::VALUE_NONE, 'Update the local vault.')
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command removes a secret from the vault.
|
||||
|
||||
<info>%command.full_name% <name></info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
$vault = $input->getOption('local') ? $this->localVault : $this->vault;
|
||||
|
||||
if (null === $vault) {
|
||||
$io->error('The local vault is disabled.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($vault->remove($name = $input->getArgument('name'))) {
|
||||
$io->success($vault->getLastMessage() ?? 'Secret was removed from the vault.');
|
||||
} else {
|
||||
$io->comment($vault->getLastMessage() ?? 'Secret was not found in the vault.');
|
||||
}
|
||||
|
||||
if ($this->vault === $vault && null !== $this->localVault->reveal($name)) {
|
||||
$io->comment('Note that this secret is overridden in the local vault.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if (!$input->mustSuggestArgumentValuesFor('name')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$vaultKeys = array_keys($this->vault->list(false));
|
||||
if ($input->getOption('local')) {
|
||||
if (null === $this->localVault) {
|
||||
return;
|
||||
}
|
||||
$vaultKeys = array_intersect($vaultKeys, array_keys($this->localVault->list(false)));
|
||||
}
|
||||
|
||||
$suggestions->suggestValues($vaultKeys);
|
||||
}
|
||||
}
|
||||
76
vendor/symfony/framework-bundle/Command/SecretsRevealCommand.php
vendored
Normal file
76
vendor/symfony/framework-bundle/Command/SecretsRevealCommand.php
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
#[AsCommand(name: 'secrets:reveal', description: 'Reveal the value of a secret')]
|
||||
final class SecretsRevealCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private readonly AbstractVault $vault,
|
||||
private readonly ?AbstractVault $localVault = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'The name of the secret to reveal', null, fn () => array_keys($this->vault->list()))
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command reveals a stored secret.
|
||||
|
||||
<info>%command.full_name%</info>
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
|
||||
|
||||
$secrets = $this->vault->list(true);
|
||||
$localSecrets = $this->localVault?->list(true);
|
||||
|
||||
$name = (string) $input->getArgument('name');
|
||||
|
||||
if (null !== $localSecrets && \array_key_exists($name, $localSecrets)) {
|
||||
$io->writeln($localSecrets[$name]);
|
||||
} else {
|
||||
if (!\array_key_exists($name, $secrets)) {
|
||||
$io->error(\sprintf('The secret "%s" does not exist.', $name));
|
||||
|
||||
return self::INVALID;
|
||||
} elseif (null === $secrets[$name]) {
|
||||
$io->error(\sprintf('The secret "%s" could not be decrypted.', $name));
|
||||
|
||||
return self::INVALID;
|
||||
}
|
||||
|
||||
$io->writeln($secrets[$name]);
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
}
|
||||
143
vendor/symfony/framework-bundle/Command/SecretsSetCommand.php
vendored
Normal file
143
vendor/symfony/framework-bundle/Command/SecretsSetCommand.php
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Secrets\AbstractVault;
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
/**
|
||||
* @author Tobias Schultze <http://tobion.de>
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
#[AsCommand(name: 'secrets:set', description: 'Set a secret in the vault')]
|
||||
final class SecretsSetCommand extends Command
|
||||
{
|
||||
public function __construct(
|
||||
private AbstractVault $vault,
|
||||
private ?AbstractVault $localVault = null,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->addArgument('name', InputArgument::REQUIRED, 'The name of the secret')
|
||||
->addArgument('file', InputArgument::OPTIONAL, 'A file where to read the secret from or "-" for reading from STDIN')
|
||||
->addOption('local', 'l', InputOption::VALUE_NONE, 'Update the local vault.')
|
||||
->addOption('random', 'r', InputOption::VALUE_OPTIONAL, 'Generate a random value.', false)
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command stores a secret in the vault.
|
||||
|
||||
<info>%command.full_name% <name></info>
|
||||
|
||||
To reference secrets in services.yaml or any other config
|
||||
files, use <info>"%env(<name>)%"</info>.
|
||||
|
||||
By default, the secret value should be entered interactively.
|
||||
Alternatively, provide a file where to read the secret from:
|
||||
|
||||
<info>php %command.full_name% <name> filename</info>
|
||||
|
||||
Use "-" as a file name to read from STDIN:
|
||||
|
||||
<info>cat filename | php %command.full_name% <name> -</info>
|
||||
|
||||
Use <info>--local</info> to override secrets for local needs.
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$errOutput = $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output;
|
||||
$io = new SymfonyStyle($input, $errOutput);
|
||||
$name = $input->getArgument('name');
|
||||
$vault = $input->getOption('local') ? $this->localVault : $this->vault;
|
||||
|
||||
if (null === $vault) {
|
||||
$io->error('The local vault is disabled.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($this->localVault === $vault && !\array_key_exists($name, $this->vault->list())) {
|
||||
$io->error(\sprintf('Secret "%s" does not exist in the vault, you cannot override it locally.', $name));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (0 < $random = $input->getOption('random') ?? 16) {
|
||||
$value = strtr(substr(base64_encode(random_bytes($random)), 0, $random), '+/', '-_');
|
||||
} elseif (!$file = $input->getArgument('file')) {
|
||||
$value = $io->askHidden('Please type the secret value');
|
||||
|
||||
if (null === $value) {
|
||||
$io->warning('No value provided: using empty string');
|
||||
$value = '';
|
||||
}
|
||||
} elseif ('-' === $file) {
|
||||
$value = file_get_contents('php://stdin');
|
||||
} elseif (is_file($file) && is_readable($file)) {
|
||||
$value = file_get_contents($file);
|
||||
} elseif (!is_file($file)) {
|
||||
throw new \InvalidArgumentException(\sprintf('File not found: "%s".', $file));
|
||||
} elseif (!is_readable($file)) {
|
||||
throw new \InvalidArgumentException(\sprintf('File is not readable: "%s".', $file));
|
||||
}
|
||||
|
||||
if ($vault->generateKeys()) {
|
||||
$io->success($vault->getLastMessage());
|
||||
|
||||
if ($this->vault === $vault) {
|
||||
$io->caution('DO NOT COMMIT THE DECRYPTION KEY FOR THE PROD ENVIRONMENT⚠️');
|
||||
}
|
||||
}
|
||||
|
||||
$vault->seal($name, $value);
|
||||
|
||||
$io->success($vault->getLastMessage() ?? 'Secret was successfully stored in the vault.');
|
||||
|
||||
if (0 < $random) {
|
||||
$errOutput->write(' // The generated random value is: <comment>');
|
||||
$output->write($value);
|
||||
$errOutput->writeln('</comment>');
|
||||
$io->newLine();
|
||||
}
|
||||
|
||||
if ($this->vault === $vault && null !== $this->localVault->reveal($name)) {
|
||||
$io->comment('Note that this secret is overridden in the local vault.');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('name')) {
|
||||
$suggestions->suggestValues(array_keys($this->vault->list(false)));
|
||||
}
|
||||
}
|
||||
}
|
||||
400
vendor/symfony/framework-bundle/Command/TranslationDebugCommand.php
vendored
Normal file
400
vendor/symfony/framework-bundle/Command/TranslationDebugCommand.php
vendored
Normal file
@@ -0,0 +1,400 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\Translation\Catalogue\MergeOperation;
|
||||
use Symfony\Component\Translation\DataCollectorTranslator;
|
||||
use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
||||
use Symfony\Component\Translation\LoggingTranslator;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\Reader\TranslationReaderInterface;
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
/**
|
||||
* Helps finding unused or missing translation messages in a given locale
|
||||
* and comparing them with the fallback ones.
|
||||
*
|
||||
* @author Florian Voutzinos <florian@voutzinos.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'debug:translation', description: 'Display translation messages information')]
|
||||
class TranslationDebugCommand extends Command
|
||||
{
|
||||
public const EXIT_CODE_GENERAL_ERROR = 64;
|
||||
public const EXIT_CODE_MISSING = 65;
|
||||
public const EXIT_CODE_UNUSED = 66;
|
||||
public const EXIT_CODE_FALLBACK = 68;
|
||||
public const MESSAGE_MISSING = 0;
|
||||
public const MESSAGE_UNUSED = 1;
|
||||
public const MESSAGE_EQUALS_FALLBACK = 2;
|
||||
|
||||
public function __construct(
|
||||
private TranslatorInterface $translator,
|
||||
private TranslationReaderInterface $reader,
|
||||
private ExtractorInterface $extractor,
|
||||
private ?string $defaultTransPath = null,
|
||||
private ?string $defaultViewsPath = null,
|
||||
private array $transPaths = [],
|
||||
private array $codePaths = [],
|
||||
private array $enabledLocales = [],
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
|
||||
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages'),
|
||||
new InputOption('domain', null, InputOption::VALUE_REQUIRED, 'The messages domain'),
|
||||
new InputOption('only-missing', null, InputOption::VALUE_NONE, 'Display only missing messages'),
|
||||
new InputOption('only-unused', null, InputOption::VALUE_NONE, 'Display only unused messages'),
|
||||
new InputOption('all', null, InputOption::VALUE_NONE, 'Load messages from all registered bundles'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command helps finding unused or missing translation
|
||||
messages and comparing them with the fallback ones by inspecting the
|
||||
templates and translation files of a given bundle or the default translations directory.
|
||||
|
||||
You can display information about bundle translations in a specific locale:
|
||||
|
||||
<info>php %command.full_name% en AcmeDemoBundle</info>
|
||||
|
||||
You can also specify a translation domain for the search:
|
||||
|
||||
<info>php %command.full_name% --domain=messages en AcmeDemoBundle</info>
|
||||
|
||||
You can only display missing messages:
|
||||
|
||||
<info>php %command.full_name% --only-missing en AcmeDemoBundle</info>
|
||||
|
||||
You can only display unused messages:
|
||||
|
||||
<info>php %command.full_name% --only-unused en AcmeDemoBundle</info>
|
||||
|
||||
You can display information about application translations in a specific locale:
|
||||
|
||||
<info>php %command.full_name% en</info>
|
||||
|
||||
You can display information about translations in all registered bundles in a specific locale:
|
||||
|
||||
<info>php %command.full_name% --all en</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$locale = $input->getArgument('locale');
|
||||
$domain = $input->getOption('domain');
|
||||
|
||||
$exitCode = self::SUCCESS;
|
||||
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
// Define Root Paths
|
||||
$transPaths = $this->getRootTransPaths();
|
||||
$codePaths = $this->getRootCodePaths($kernel);
|
||||
|
||||
// Override with provided Bundle info
|
||||
if (null !== $input->getArgument('bundle')) {
|
||||
try {
|
||||
$bundle = $kernel->getBundle($input->getArgument('bundle'));
|
||||
$bundleDir = $bundle->getPath();
|
||||
$transPaths = [is_dir($bundleDir.'/Resources/translations') ? $bundleDir.'/Resources/translations' : $bundleDir.'/translations'];
|
||||
$codePaths = [is_dir($bundleDir.'/Resources/views') ? $bundleDir.'/Resources/views' : $bundleDir.'/templates'];
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath;
|
||||
}
|
||||
if ($this->defaultViewsPath) {
|
||||
$codePaths[] = $this->defaultViewsPath;
|
||||
}
|
||||
} catch (\InvalidArgumentException) {
|
||||
// such a bundle does not exist, so treat the argument as path
|
||||
$path = $input->getArgument('bundle');
|
||||
|
||||
$transPaths = [$path.'/translations'];
|
||||
$codePaths = [$path.'/templates'];
|
||||
|
||||
if (!is_dir($transPaths[0])) {
|
||||
throw new InvalidArgumentException(\sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
|
||||
}
|
||||
}
|
||||
} elseif ($input->getOption('all')) {
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
$bundleDir = $bundle->getPath();
|
||||
$transPaths[] = is_dir($bundleDir.'/Resources/translations') ? $bundleDir.'/Resources/translations' : $bundle->getPath().'/translations';
|
||||
$codePaths[] = is_dir($bundleDir.'/Resources/views') ? $bundleDir.'/Resources/views' : $bundle->getPath().'/templates';
|
||||
}
|
||||
}
|
||||
|
||||
// Extract used messages
|
||||
$extractedCatalogue = $this->extractMessages($locale, $codePaths);
|
||||
|
||||
// Load defined messages
|
||||
$currentCatalogue = $this->loadCurrentMessages($locale, $transPaths);
|
||||
|
||||
// Merge defined and extracted messages to get all message ids
|
||||
$mergeOperation = new MergeOperation($extractedCatalogue, $currentCatalogue);
|
||||
$allMessages = $mergeOperation->getResult()->all($domain);
|
||||
if (null !== $domain) {
|
||||
$allMessages = [$domain => $allMessages];
|
||||
}
|
||||
|
||||
// No defined or extracted messages
|
||||
if (!$allMessages || null !== $domain && empty($allMessages[$domain])) {
|
||||
$outputMessage = \sprintf('No defined or extracted messages for locale "%s"', $locale);
|
||||
|
||||
if (null !== $domain) {
|
||||
$outputMessage .= \sprintf(' and domain "%s"', $domain);
|
||||
}
|
||||
|
||||
$io->getErrorStyle()->warning($outputMessage);
|
||||
|
||||
return self::EXIT_CODE_GENERAL_ERROR;
|
||||
}
|
||||
|
||||
// Load the fallback catalogues
|
||||
$fallbackCatalogues = $this->loadFallbackCatalogues($locale, $transPaths);
|
||||
|
||||
// Display header line
|
||||
$headers = ['State', 'Domain', 'Id', \sprintf('Message Preview (%s)', $locale)];
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
$headers[] = \sprintf('Fallback Message Preview (%s)', $fallbackCatalogue->getLocale());
|
||||
}
|
||||
$rows = [];
|
||||
// Iterate all message ids and determine their state
|
||||
foreach ($allMessages as $domain => $messages) {
|
||||
foreach (array_keys($messages) as $messageId) {
|
||||
$value = $currentCatalogue->get($messageId, $domain);
|
||||
$states = [];
|
||||
|
||||
if ($extractedCatalogue->defines($messageId, $domain)) {
|
||||
if (!$currentCatalogue->defines($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_MISSING;
|
||||
|
||||
if (!$input->getOption('only-unused')) {
|
||||
$exitCode |= self::EXIT_CODE_MISSING;
|
||||
}
|
||||
}
|
||||
} elseif ($currentCatalogue->defines($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_UNUSED;
|
||||
|
||||
if (!$input->getOption('only-missing')) {
|
||||
$exitCode |= self::EXIT_CODE_UNUSED;
|
||||
}
|
||||
}
|
||||
|
||||
if (!\in_array(self::MESSAGE_UNUSED, $states, true) && $input->getOption('only-unused')
|
||||
|| !\in_array(self::MESSAGE_MISSING, $states, true) && $input->getOption('only-missing')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
if ($fallbackCatalogue->defines($messageId, $domain) && $value === $fallbackCatalogue->get($messageId, $domain)) {
|
||||
$states[] = self::MESSAGE_EQUALS_FALLBACK;
|
||||
|
||||
$exitCode |= self::EXIT_CODE_FALLBACK;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$row = [$this->formatStates($states), $domain, $this->formatId($messageId), $this->sanitizeString($value)];
|
||||
foreach ($fallbackCatalogues as $fallbackCatalogue) {
|
||||
$row[] = $this->sanitizeString($fallbackCatalogue->get($messageId, $domain));
|
||||
}
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
$io->table($headers, $rows);
|
||||
|
||||
return $exitCode;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('locale')) {
|
||||
$suggestions->suggestValues($this->enabledLocales);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
if ($input->mustSuggestArgumentValuesFor('bundle')) {
|
||||
$availableBundles = [];
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
$availableBundles[] = $bundle->getName();
|
||||
|
||||
if ($extension = $bundle->getContainerExtension()) {
|
||||
$availableBundles[] = $extension->getAlias();
|
||||
}
|
||||
}
|
||||
|
||||
$suggestions->suggestValues($availableBundles);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('domain')) {
|
||||
$locale = $input->getArgument('locale');
|
||||
|
||||
$mergeOperation = new MergeOperation(
|
||||
$this->extractMessages($locale, $this->getRootCodePaths($kernel)),
|
||||
$this->loadCurrentMessages($locale, $this->getRootTransPaths())
|
||||
);
|
||||
|
||||
$suggestions->suggestValues($mergeOperation->getDomains());
|
||||
}
|
||||
}
|
||||
|
||||
private function formatState(int $state): string
|
||||
{
|
||||
if (self::MESSAGE_MISSING === $state) {
|
||||
return '<error> missing </error>';
|
||||
}
|
||||
|
||||
if (self::MESSAGE_UNUSED === $state) {
|
||||
return '<comment> unused </comment>';
|
||||
}
|
||||
|
||||
if (self::MESSAGE_EQUALS_FALLBACK === $state) {
|
||||
return '<info> fallback </info>';
|
||||
}
|
||||
|
||||
return $state;
|
||||
}
|
||||
|
||||
private function formatStates(array $states): string
|
||||
{
|
||||
$result = [];
|
||||
foreach ($states as $state) {
|
||||
$result[] = $this->formatState($state);
|
||||
}
|
||||
|
||||
return implode(' ', $result);
|
||||
}
|
||||
|
||||
private function formatId(string $id): string
|
||||
{
|
||||
return \sprintf('<fg=cyan;options=bold>%s</>', $id);
|
||||
}
|
||||
|
||||
private function sanitizeString(string $string, int $length = 40): string
|
||||
{
|
||||
$string = trim(preg_replace('/\s+/', ' ', $string));
|
||||
|
||||
if (false !== $encoding = mb_detect_encoding($string, null, true)) {
|
||||
if (mb_strlen($string, $encoding) > $length) {
|
||||
return mb_substr($string, 0, $length - 3, $encoding).'...';
|
||||
}
|
||||
} elseif (\strlen($string) > $length) {
|
||||
return substr($string, 0, $length - 3).'...';
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
private function extractMessages(string $locale, array $transPaths): MessageCatalogue
|
||||
{
|
||||
$extractedCatalogue = new MessageCatalogue($locale);
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path) || is_file($path)) {
|
||||
$this->extractor->extract($path, $extractedCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
return $extractedCatalogue;
|
||||
}
|
||||
|
||||
private function loadCurrentMessages(string $locale, array $transPaths): MessageCatalogue
|
||||
{
|
||||
$currentCatalogue = new MessageCatalogue($locale);
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$this->reader->read($path, $currentCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
return $currentCatalogue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MessageCatalogue[]
|
||||
*/
|
||||
private function loadFallbackCatalogues(string $locale, array $transPaths): array
|
||||
{
|
||||
$fallbackCatalogues = [];
|
||||
if ($this->translator instanceof Translator || $this->translator instanceof DataCollectorTranslator || $this->translator instanceof LoggingTranslator) {
|
||||
foreach ($this->translator->getFallbackLocales() as $fallbackLocale) {
|
||||
if ($fallbackLocale === $locale) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$fallbackCatalogue = new MessageCatalogue($fallbackLocale);
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$this->reader->read($path, $fallbackCatalogue);
|
||||
}
|
||||
}
|
||||
$fallbackCatalogues[] = $fallbackCatalogue;
|
||||
}
|
||||
}
|
||||
|
||||
return $fallbackCatalogues;
|
||||
}
|
||||
|
||||
private function getRootTransPaths(): array
|
||||
{
|
||||
$transPaths = $this->transPaths;
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath;
|
||||
}
|
||||
|
||||
return $transPaths;
|
||||
}
|
||||
|
||||
private function getRootCodePaths(KernelInterface $kernel): array
|
||||
{
|
||||
$codePaths = $this->codePaths;
|
||||
$codePaths[] = $kernel->getProjectDir().'/src';
|
||||
if ($this->defaultViewsPath) {
|
||||
$codePaths[] = $this->defaultViewsPath;
|
||||
}
|
||||
|
||||
return $codePaths;
|
||||
}
|
||||
}
|
||||
503
vendor/symfony/framework-bundle/Command/TranslationExtractCommand.php
vendored
Normal file
503
vendor/symfony/framework-bundle/Command/TranslationExtractCommand.php
vendored
Normal file
@@ -0,0 +1,503 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\Translation\Catalogue\MergeOperation;
|
||||
use Symfony\Component\Translation\Catalogue\TargetOperation;
|
||||
use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
||||
use Symfony\Component\Translation\MessageCatalogue;
|
||||
use Symfony\Component\Translation\MessageCatalogueInterface;
|
||||
use Symfony\Component\Translation\Reader\TranslationReaderInterface;
|
||||
use Symfony\Component\Translation\Writer\TranslationWriterInterface;
|
||||
|
||||
/**
|
||||
* A command that parses templates to extract translation messages and adds them
|
||||
* into the translation files.
|
||||
*
|
||||
* @author Michel Salib <michelsalib@hotmail.com>
|
||||
*/
|
||||
#[AsCommand(name: 'translation:extract', description: 'Extract missing translations keys from code to translation files')]
|
||||
class TranslationExtractCommand extends Command
|
||||
{
|
||||
private const ASC = 'asc';
|
||||
private const DESC = 'desc';
|
||||
private const SORT_ORDERS = [self::ASC, self::DESC];
|
||||
private const FORMATS = [
|
||||
'xlf12' => ['xlf', '1.2'],
|
||||
'xlf20' => ['xlf', '2.0'],
|
||||
];
|
||||
private const NO_FILL_PREFIX = "\0NoFill\0";
|
||||
|
||||
public function __construct(
|
||||
private TranslationWriterInterface $writer,
|
||||
private TranslationReaderInterface $reader,
|
||||
private ExtractorInterface $extractor,
|
||||
private string $defaultLocale,
|
||||
private ?string $defaultTransPath = null,
|
||||
private ?string $defaultViewsPath = null,
|
||||
private array $transPaths = [],
|
||||
private array $codePaths = [],
|
||||
private array $enabledLocales = [],
|
||||
) {
|
||||
parent::__construct();
|
||||
|
||||
if (!method_exists($writer, 'getFormats')) {
|
||||
throw new \InvalidArgumentException(\sprintf('The writer class "%s" does not implement the "getFormats()" method.', $writer::class));
|
||||
}
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('locale', InputArgument::REQUIRED, 'The locale'),
|
||||
new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages'),
|
||||
new InputOption('prefix', null, InputOption::VALUE_REQUIRED, 'Override the default prefix', '__'),
|
||||
new InputOption('no-fill', null, InputOption::VALUE_NONE, 'Extract translation keys without filling in values'),
|
||||
new InputOption('format', null, InputOption::VALUE_REQUIRED, 'Override the default output format', 'xlf12'),
|
||||
new InputOption('dump-messages', null, InputOption::VALUE_NONE, 'Should the messages be dumped in the console'),
|
||||
new InputOption('force', null, InputOption::VALUE_NONE, 'Should the extract be done'),
|
||||
new InputOption('clean', null, InputOption::VALUE_NONE, 'Should clean not found messages'),
|
||||
new InputOption('domain', null, InputOption::VALUE_REQUIRED, 'Specify the domain to extract'),
|
||||
new InputOption('sort', null, InputOption::VALUE_REQUIRED, 'Return list of messages sorted alphabetically'),
|
||||
new InputOption('as-tree', null, InputOption::VALUE_REQUIRED, 'Dump the messages as a tree-like structure: The given value defines the level where to switch to inline YAML'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command extracts translation strings from templates
|
||||
of a given bundle or the default translations directory. It can display them or merge
|
||||
the new ones into the translation files.
|
||||
|
||||
When new translation strings are found it can automatically add a prefix to the translation
|
||||
message. However, if the <comment>--no-fill</comment> option is used, the <comment>--prefix</comment>
|
||||
option has no effect, since the translation values are left empty.
|
||||
|
||||
Example running against a Bundle (AcmeBundle)
|
||||
|
||||
<info>php %command.full_name% --dump-messages en AcmeBundle</info>
|
||||
<info>php %command.full_name% --force --prefix="new_" fr AcmeBundle</info>
|
||||
|
||||
Example running against default messages directory
|
||||
|
||||
<info>php %command.full_name% --dump-messages en</info>
|
||||
<info>php %command.full_name% --force --prefix="new_" fr</info>
|
||||
|
||||
You can sort the output with the <comment>--sort</> flag:
|
||||
|
||||
<info>php %command.full_name% --dump-messages --sort=asc en AcmeBundle</info>
|
||||
<info>php %command.full_name% --force --sort=desc fr</info>
|
||||
|
||||
You can dump a tree-like structure using the yaml format with <comment>--as-tree</> flag:
|
||||
|
||||
<info>php %command.full_name% --force --format=yaml --as-tree=3 en AcmeBundle</info>
|
||||
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$errorIo = $io->getErrorStyle();
|
||||
|
||||
// check presence of force or dump-message
|
||||
if (true !== $input->getOption('force') && true !== $input->getOption('dump-messages')) {
|
||||
$errorIo->error('You must choose one of --force or --dump-messages');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$format = $input->getOption('format');
|
||||
$xliffVersion = '1.2';
|
||||
|
||||
if (\array_key_exists($format, self::FORMATS)) {
|
||||
[$format, $xliffVersion] = self::FORMATS[$format];
|
||||
}
|
||||
|
||||
// check format
|
||||
$supportedFormats = $this->writer->getFormats();
|
||||
if (!\in_array($format, $supportedFormats, true)) {
|
||||
$errorIo->error(['Wrong output format', 'Supported formats are: '.implode(', ', $supportedFormats).', xlf12 and xlf20.']);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
|
||||
// Define Root Paths
|
||||
$transPaths = $this->getRootTransPaths();
|
||||
$codePaths = $this->getRootCodePaths($kernel);
|
||||
|
||||
$currentName = 'default directory';
|
||||
|
||||
// Override with provided Bundle info
|
||||
if (null !== $input->getArgument('bundle')) {
|
||||
try {
|
||||
$foundBundle = $kernel->getBundle($input->getArgument('bundle'));
|
||||
$bundleDir = $foundBundle->getPath();
|
||||
$transPaths = [is_dir($bundleDir.'/Resources/translations') ? $bundleDir.'/Resources/translations' : $bundleDir.'/translations'];
|
||||
$codePaths = [is_dir($bundleDir.'/Resources/views') ? $bundleDir.'/Resources/views' : $bundleDir.'/templates'];
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath;
|
||||
}
|
||||
if ($this->defaultViewsPath) {
|
||||
$codePaths[] = $this->defaultViewsPath;
|
||||
}
|
||||
$currentName = $foundBundle->getName();
|
||||
} catch (\InvalidArgumentException) {
|
||||
// such a bundle does not exist, so treat the argument as path
|
||||
$path = $input->getArgument('bundle');
|
||||
|
||||
$transPaths = [$path.'/translations'];
|
||||
$codePaths = [$path.'/templates'];
|
||||
|
||||
if (!is_dir($transPaths[0])) {
|
||||
throw new InvalidArgumentException(\sprintf('"%s" is neither an enabled bundle nor a directory.', $transPaths[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$io->title('Translation Messages Extractor and Dumper');
|
||||
$io->comment(\sprintf('Generating "<info>%s</info>" translation files for "<info>%s</info>"', $input->getArgument('locale'), $currentName));
|
||||
|
||||
$io->comment('Parsing templates...');
|
||||
$prefix = $input->getOption('no-fill') ? self::NO_FILL_PREFIX : $input->getOption('prefix');
|
||||
$extractedCatalogue = $this->extractMessages($input->getArgument('locale'), $codePaths, $prefix);
|
||||
|
||||
$io->comment('Loading translation files...');
|
||||
$currentCatalogue = $this->loadCurrentMessages($input->getArgument('locale'), $transPaths);
|
||||
|
||||
if (null !== $domain = $input->getOption('domain')) {
|
||||
$currentCatalogue = $this->filterCatalogue($currentCatalogue, $domain);
|
||||
$extractedCatalogue = $this->filterCatalogue($extractedCatalogue, $domain);
|
||||
}
|
||||
|
||||
// process catalogues
|
||||
$operation = $input->getOption('clean')
|
||||
? new TargetOperation($currentCatalogue, $extractedCatalogue)
|
||||
: new MergeOperation($currentCatalogue, $extractedCatalogue);
|
||||
|
||||
// Exit if no messages found.
|
||||
if (!\count($operation->getDomains())) {
|
||||
$errorIo->warning('No translation messages were found.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
$resultMessage = 'Translation files were successfully updated';
|
||||
|
||||
$operation->moveMessagesToIntlDomainsIfPossible('new');
|
||||
|
||||
if ($sort = $input->getOption('sort')) {
|
||||
$sort = strtolower($sort);
|
||||
if (!\in_array($sort, self::SORT_ORDERS, true)) {
|
||||
$errorIo->error(['Wrong sort order', 'Supported formats are: '.implode(', ', self::SORT_ORDERS).'.']);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// show compiled list of messages
|
||||
if (true === $input->getOption('dump-messages')) {
|
||||
$extractedMessagesCount = 0;
|
||||
$io->newLine();
|
||||
foreach ($operation->getDomains() as $domain) {
|
||||
$newKeys = array_keys($operation->getNewMessages($domain));
|
||||
$allKeys = array_keys($operation->getMessages($domain));
|
||||
|
||||
$list = array_merge(
|
||||
array_diff($allKeys, $newKeys),
|
||||
array_map(fn ($id) => \sprintf('<fg=green>%s</>', $id), $newKeys),
|
||||
array_map(fn ($id) => \sprintf('<fg=red>%s</>', $id), array_keys($operation->getObsoleteMessages($domain)))
|
||||
);
|
||||
|
||||
$domainMessagesCount = \count($list);
|
||||
|
||||
if (self::DESC === $sort) {
|
||||
rsort($list);
|
||||
} else {
|
||||
sort($list);
|
||||
}
|
||||
|
||||
$io->section(\sprintf('Messages extracted for domain "<info>%s</info>" (%d message%s)', $domain, $domainMessagesCount, $domainMessagesCount > 1 ? 's' : ''));
|
||||
$io->listing($list);
|
||||
|
||||
$extractedMessagesCount += $domainMessagesCount;
|
||||
}
|
||||
|
||||
if ('xlf' === $format) {
|
||||
$io->comment(\sprintf('Xliff output version is <info>%s</info>', $xliffVersion));
|
||||
}
|
||||
|
||||
$resultMessage = \sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was');
|
||||
}
|
||||
|
||||
// save the files
|
||||
if (true === $input->getOption('force')) {
|
||||
$io->comment('Writing files...');
|
||||
|
||||
$bundleTransPath = false;
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$bundleTransPath = $path;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$bundleTransPath) {
|
||||
$bundleTransPath = end($transPaths);
|
||||
}
|
||||
|
||||
$operationResult = $operation->getResult();
|
||||
if ($sort) {
|
||||
$operationResult = $this->sortCatalogue($operationResult, $sort);
|
||||
}
|
||||
|
||||
if (true === $input->getOption('no-fill')) {
|
||||
$this->removeNoFillTranslations($operationResult);
|
||||
}
|
||||
|
||||
$this->writer->write($operationResult, $format, ['path' => $bundleTransPath, 'default_locale' => $this->defaultLocale, 'xliff_version' => $xliffVersion, 'as_tree' => $input->getOption('as-tree'), 'inline' => $input->getOption('as-tree') ?? 0]);
|
||||
|
||||
if (true === $input->getOption('dump-messages')) {
|
||||
$resultMessage .= ' and translation files were updated';
|
||||
}
|
||||
}
|
||||
|
||||
$io->success($resultMessage.'.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('locale')) {
|
||||
$suggestions->suggestValues($this->enabledLocales);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var KernelInterface $kernel */
|
||||
$kernel = $this->getApplication()->getKernel();
|
||||
if ($input->mustSuggestArgumentValuesFor('bundle')) {
|
||||
$bundles = [];
|
||||
|
||||
foreach ($kernel->getBundles() as $bundle) {
|
||||
$bundles[] = $bundle->getName();
|
||||
if ($bundle->getContainerExtension()) {
|
||||
$bundles[] = $bundle->getContainerExtension()->getAlias();
|
||||
}
|
||||
}
|
||||
|
||||
$suggestions->suggestValues($bundles);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('format')) {
|
||||
$suggestions->suggestValues(array_merge(
|
||||
$this->writer->getFormats(),
|
||||
array_keys(self::FORMATS)
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('domain') && $locale = $input->getArgument('locale')) {
|
||||
$extractedCatalogue = $this->extractMessages($locale, $this->getRootCodePaths($kernel), $input->getOption('prefix'));
|
||||
|
||||
$currentCatalogue = $this->loadCurrentMessages($locale, $this->getRootTransPaths());
|
||||
|
||||
// process catalogues
|
||||
$operation = $input->getOption('clean')
|
||||
? new TargetOperation($currentCatalogue, $extractedCatalogue)
|
||||
: new MergeOperation($currentCatalogue, $extractedCatalogue);
|
||||
|
||||
$suggestions->suggestValues($operation->getDomains());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('sort')) {
|
||||
$suggestions->suggestValues(self::SORT_ORDERS);
|
||||
}
|
||||
}
|
||||
|
||||
private function filterCatalogue(MessageCatalogue $catalogue, string $domain): MessageCatalogue
|
||||
{
|
||||
$filteredCatalogue = new MessageCatalogue($catalogue->getLocale());
|
||||
|
||||
// extract intl-icu messages only
|
||||
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
|
||||
if ($intlMessages = $catalogue->all($intlDomain)) {
|
||||
$filteredCatalogue->add($intlMessages, $intlDomain);
|
||||
}
|
||||
|
||||
// extract all messages and subtract intl-icu messages
|
||||
if ($messages = array_diff($catalogue->all($domain), $intlMessages)) {
|
||||
$filteredCatalogue->add($messages, $domain);
|
||||
}
|
||||
foreach ($catalogue->getResources() as $resource) {
|
||||
$filteredCatalogue->addResource($resource);
|
||||
}
|
||||
|
||||
if ($metadata = $catalogue->getMetadata('', $intlDomain)) {
|
||||
foreach ($metadata as $k => $v) {
|
||||
$filteredCatalogue->setMetadata($k, $v, $intlDomain);
|
||||
}
|
||||
}
|
||||
|
||||
if ($metadata = $catalogue->getMetadata('', $domain)) {
|
||||
foreach ($metadata as $k => $v) {
|
||||
$filteredCatalogue->setMetadata($k, $v, $domain);
|
||||
}
|
||||
}
|
||||
|
||||
return $filteredCatalogue;
|
||||
}
|
||||
|
||||
private function sortCatalogue(MessageCatalogue $catalogue, string $sort): MessageCatalogue
|
||||
{
|
||||
$sortedCatalogue = new MessageCatalogue($catalogue->getLocale());
|
||||
|
||||
foreach ($catalogue->getDomains() as $domain) {
|
||||
// extract intl-icu messages only
|
||||
$intlDomain = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX;
|
||||
if ($intlMessages = $catalogue->all($intlDomain)) {
|
||||
if (self::DESC === $sort) {
|
||||
krsort($intlMessages);
|
||||
} elseif (self::ASC === $sort) {
|
||||
ksort($intlMessages);
|
||||
}
|
||||
|
||||
$sortedCatalogue->add($intlMessages, $intlDomain);
|
||||
}
|
||||
|
||||
// extract all messages and subtract intl-icu messages
|
||||
if ($messages = array_diff($catalogue->all($domain), $intlMessages)) {
|
||||
if (self::DESC === $sort) {
|
||||
krsort($messages);
|
||||
} elseif (self::ASC === $sort) {
|
||||
ksort($messages);
|
||||
}
|
||||
|
||||
$sortedCatalogue->add($messages, $domain);
|
||||
}
|
||||
|
||||
if ($metadata = $catalogue->getMetadata('', $intlDomain)) {
|
||||
foreach ($metadata as $k => $v) {
|
||||
$sortedCatalogue->setMetadata($k, $v, $intlDomain);
|
||||
}
|
||||
}
|
||||
|
||||
if ($metadata = $catalogue->getMetadata('', $domain)) {
|
||||
foreach ($metadata as $k => $v) {
|
||||
$sortedCatalogue->setMetadata($k, $v, $domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($catalogue->getResources() as $resource) {
|
||||
$sortedCatalogue->addResource($resource);
|
||||
}
|
||||
|
||||
return $sortedCatalogue;
|
||||
}
|
||||
|
||||
private function extractMessages(string $locale, array $transPaths, string $prefix): MessageCatalogue
|
||||
{
|
||||
$extractedCatalogue = new MessageCatalogue($locale);
|
||||
$this->extractor->setPrefix($prefix);
|
||||
$transPaths = $this->filterDuplicateTransPaths($transPaths);
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path) || is_file($path)) {
|
||||
$this->extractor->extract($path, $extractedCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
return $extractedCatalogue;
|
||||
}
|
||||
|
||||
private function filterDuplicateTransPaths(array $transPaths): array
|
||||
{
|
||||
$transPaths = array_filter(array_map('realpath', $transPaths));
|
||||
|
||||
sort($transPaths);
|
||||
|
||||
$filteredPaths = [];
|
||||
|
||||
foreach ($transPaths as $path) {
|
||||
foreach ($filteredPaths as $filteredPath) {
|
||||
if (str_starts_with($path, $filteredPath.\DIRECTORY_SEPARATOR)) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
$filteredPaths[] = $path;
|
||||
}
|
||||
|
||||
return $filteredPaths;
|
||||
}
|
||||
|
||||
private function loadCurrentMessages(string $locale, array $transPaths): MessageCatalogue
|
||||
{
|
||||
$currentCatalogue = new MessageCatalogue($locale);
|
||||
foreach ($transPaths as $path) {
|
||||
if (is_dir($path)) {
|
||||
$this->reader->read($path, $currentCatalogue);
|
||||
}
|
||||
}
|
||||
|
||||
return $currentCatalogue;
|
||||
}
|
||||
|
||||
private function getRootTransPaths(): array
|
||||
{
|
||||
$transPaths = $this->transPaths;
|
||||
if ($this->defaultTransPath) {
|
||||
$transPaths[] = $this->defaultTransPath;
|
||||
}
|
||||
|
||||
return $transPaths;
|
||||
}
|
||||
|
||||
private function getRootCodePaths(KernelInterface $kernel): array
|
||||
{
|
||||
$codePaths = $this->codePaths;
|
||||
$codePaths[] = $kernel->getProjectDir().'/src';
|
||||
if ($this->defaultViewsPath) {
|
||||
$codePaths[] = $this->defaultViewsPath;
|
||||
}
|
||||
|
||||
return $codePaths;
|
||||
}
|
||||
|
||||
private function removeNoFillTranslations(MessageCatalogueInterface $operation): void
|
||||
{
|
||||
foreach ($operation->all('messages') as $key => $message) {
|
||||
if (str_starts_with($message, self::NO_FILL_PREFIX)) {
|
||||
$operation->set($key, '', 'messages');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
34
vendor/symfony/framework-bundle/Command/TranslationUpdateCommand.php
vendored
Normal file
34
vendor/symfony/framework-bundle/Command/TranslationUpdateCommand.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Translation\Extractor\ExtractorInterface;
|
||||
use Symfony\Component\Translation\Reader\TranslationReaderInterface;
|
||||
use Symfony\Component\Translation\Writer\TranslationWriterInterface;
|
||||
|
||||
class TranslationUpdateCommand extends TranslationExtractCommand
|
||||
{
|
||||
public function __construct(
|
||||
private TranslationWriterInterface $writer,
|
||||
private TranslationReaderInterface $reader,
|
||||
private ExtractorInterface $extractor,
|
||||
private string $defaultLocale,
|
||||
private ?string $defaultTransPath = null,
|
||||
private ?string $defaultViewsPath = null,
|
||||
private array $transPaths = [],
|
||||
private array $codePaths = [],
|
||||
private array $enabledLocales = [],
|
||||
) {
|
||||
trigger_deprecation('symfony/framework-bundle', '7.3', 'The "%s" class is deprecated, use "%s" instead.', __CLASS__, TranslationExtractCommand::class);
|
||||
parent::__construct($writer, $reader, $extractor, $defaultLocale, $defaultTransPath, $defaultViewsPath, $transPaths, $codePaths, $enabledLocales);
|
||||
}
|
||||
}
|
||||
127
vendor/symfony/framework-bundle/Command/WorkflowDumpCommand.php
vendored
Normal file
127
vendor/symfony/framework-bundle/Command/WorkflowDumpCommand.php
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Completion\CompletionInput;
|
||||
use Symfony\Component\Console\Completion\CompletionSuggestions;
|
||||
use Symfony\Component\Console\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\DependencyInjection\ServiceLocator;
|
||||
use Symfony\Component\Workflow\Dumper\GraphvizDumper;
|
||||
use Symfony\Component\Workflow\Dumper\MermaidDumper;
|
||||
use Symfony\Component\Workflow\Dumper\PlantUmlDumper;
|
||||
use Symfony\Component\Workflow\Dumper\StateMachineGraphvizDumper;
|
||||
use Symfony\Component\Workflow\Marking;
|
||||
use Symfony\Component\Workflow\StateMachine;
|
||||
|
||||
/**
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'workflow:dump', description: 'Dump a workflow')]
|
||||
class WorkflowDumpCommand extends Command
|
||||
{
|
||||
private const DUMP_FORMAT_OPTIONS = [
|
||||
'puml',
|
||||
'mermaid',
|
||||
'dot',
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
private ServiceLocator $workflows,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this
|
||||
->setDefinition([
|
||||
new InputArgument('name', InputArgument::REQUIRED, 'A workflow name'),
|
||||
new InputArgument('marking', InputArgument::IS_ARRAY, 'A marking (a list of places)'),
|
||||
new InputOption('label', 'l', InputOption::VALUE_REQUIRED, 'Label a graph'),
|
||||
new InputOption('with-metadata', null, InputOption::VALUE_NONE, 'Include the workflow\'s metadata in the dumped graph', null),
|
||||
new InputOption('dump-format', null, InputOption::VALUE_REQUIRED, 'The dump format ['.implode('|', self::DUMP_FORMAT_OPTIONS).']', 'dot'),
|
||||
])
|
||||
->setHelp(<<<'EOF'
|
||||
The <info>%command.name%</info> command dumps the graphical representation of a
|
||||
workflow in different formats
|
||||
|
||||
<info>DOT</info>: %command.full_name% <workflow name> | dot -Tpng > workflow.png
|
||||
<info>PUML</info>: %command.full_name% <workflow name> --dump-format=puml | java -jar plantuml.jar -p > workflow.png
|
||||
<info>MERMAID</info>: %command.full_name% <workflow name> --dump-format=mermaid | mmdc -o workflow.svg
|
||||
EOF
|
||||
)
|
||||
;
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$workflowName = $input->getArgument('name');
|
||||
|
||||
if (!$this->workflows->has($workflowName)) {
|
||||
throw new InvalidArgumentException(\sprintf('The workflow named "%s" cannot be found.', $workflowName));
|
||||
}
|
||||
$workflow = $this->workflows->get($workflowName);
|
||||
$type = $workflow instanceof StateMachine ? 'state_machine' : 'workflow';
|
||||
$definition = $workflow->getDefinition();
|
||||
|
||||
switch ($input->getOption('dump-format')) {
|
||||
case 'puml':
|
||||
$transitionType = 'workflow' === $type ? PlantUmlDumper::WORKFLOW_TRANSITION : PlantUmlDumper::STATEMACHINE_TRANSITION;
|
||||
$dumper = new PlantUmlDumper($transitionType);
|
||||
break;
|
||||
|
||||
case 'mermaid':
|
||||
$transitionType = 'workflow' === $type ? MermaidDumper::TRANSITION_TYPE_WORKFLOW : MermaidDumper::TRANSITION_TYPE_STATEMACHINE;
|
||||
$dumper = new MermaidDumper($transitionType);
|
||||
break;
|
||||
|
||||
case 'dot':
|
||||
default:
|
||||
$dumper = ('workflow' === $type) ? new GraphvizDumper() : new StateMachineGraphvizDumper();
|
||||
}
|
||||
|
||||
$marking = new Marking();
|
||||
|
||||
foreach ($input->getArgument('marking') as $place) {
|
||||
$marking->mark($place);
|
||||
}
|
||||
|
||||
$options = [
|
||||
'name' => $workflowName,
|
||||
'with-metadata' => $input->getOption('with-metadata'),
|
||||
'nofooter' => true,
|
||||
'label' => $input->getOption('label'),
|
||||
];
|
||||
$output->writeln($dumper->dump($definition, $marking, $options));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function complete(CompletionInput $input, CompletionSuggestions $suggestions): void
|
||||
{
|
||||
if ($input->mustSuggestArgumentValuesFor('name')) {
|
||||
$suggestions->suggestValues(array_keys($this->workflows->getProvidedServices()));
|
||||
}
|
||||
|
||||
if ($input->mustSuggestOptionValuesFor('dump-format')) {
|
||||
$suggestions->suggestValues(self::DUMP_FORMAT_OPTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
57
vendor/symfony/framework-bundle/Command/XliffLintCommand.php
vendored
Normal file
57
vendor/symfony/framework-bundle/Command/XliffLintCommand.php
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Translation\Command\XliffLintCommand as BaseLintCommand;
|
||||
|
||||
/**
|
||||
* Validates XLIFF files syntax and outputs encountered errors.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'lint:xliff', description: 'Lint an XLIFF file and outputs encountered errors')]
|
||||
class XliffLintCommand extends BaseLintCommand
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$directoryIteratorProvider = function ($directory, $default) {
|
||||
if (!is_dir($directory)) {
|
||||
$directory = $this->getApplication()->getKernel()->locateResource($directory);
|
||||
}
|
||||
|
||||
return $default($directory);
|
||||
};
|
||||
|
||||
$isReadableProvider = fn ($fileOrDirectory, $default) => str_starts_with($fileOrDirectory, '@') || $default($fileOrDirectory);
|
||||
|
||||
parent::__construct(null, $directoryIteratorProvider, $isReadableProvider);
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->setHelp($this->getHelp().<<<'EOF'
|
||||
|
||||
Or find all files in a bundle:
|
||||
|
||||
<info>php %command.full_name% @AcmeDemoBundle</info>
|
||||
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
56
vendor/symfony/framework-bundle/Command/YamlLintCommand.php
vendored
Normal file
56
vendor/symfony/framework-bundle/Command/YamlLintCommand.php
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
<?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\Bundle\FrameworkBundle\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Yaml\Command\LintCommand as BaseLintCommand;
|
||||
|
||||
/**
|
||||
* Validates YAML files syntax and outputs encountered errors.
|
||||
*
|
||||
* @author Grégoire Pineau <lyrixx@lyrixx.info>
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[AsCommand(name: 'lint:yaml', description: 'Lint a YAML file and outputs encountered errors')]
|
||||
class YamlLintCommand extends BaseLintCommand
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$directoryIteratorProvider = function ($directory, $default) {
|
||||
if (!is_dir($directory)) {
|
||||
$directory = $this->getApplication()->getKernel()->locateResource($directory);
|
||||
}
|
||||
|
||||
return $default($directory);
|
||||
};
|
||||
|
||||
$isReadableProvider = fn ($fileOrDirectory, $default) => str_starts_with($fileOrDirectory, '@') || $default($fileOrDirectory);
|
||||
|
||||
parent::__construct(null, $directoryIteratorProvider, $isReadableProvider);
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->setHelp($this->getHelp().<<<'EOF'
|
||||
|
||||
Or find all files in a bundle:
|
||||
|
||||
<info>php %command.full_name% @AcmeDemoBundle</info>
|
||||
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
221
vendor/symfony/framework-bundle/Console/Application.php
vendored
Normal file
221
vendor/symfony/framework-bundle/Console/Application.php
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
<?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\Bundle\FrameworkBundle\Console;
|
||||
|
||||
use Symfony\Component\Console\Application as BaseApplication;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Command\ListCommand;
|
||||
use Symfony\Component\Console\Command\TraceableCommand;
|
||||
use Symfony\Component\Console\Debug\CliRequest;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class Application extends BaseApplication
|
||||
{
|
||||
private bool $commandsRegistered = false;
|
||||
private array $registrationErrors = [];
|
||||
|
||||
public function __construct(
|
||||
private KernelInterface $kernel,
|
||||
) {
|
||||
parent::__construct('Symfony', Kernel::VERSION);
|
||||
|
||||
$inputDefinition = $this->getDefinition();
|
||||
$inputDefinition->addOption(new InputOption('--env', '-e', InputOption::VALUE_REQUIRED, 'The Environment name.', $kernel->getEnvironment()));
|
||||
$inputDefinition->addOption(new InputOption('--no-debug', null, InputOption::VALUE_NONE, 'Switch off debug mode.'));
|
||||
$inputDefinition->addOption(new InputOption('--profile', null, InputOption::VALUE_NONE, 'Enables profiling (requires debug).'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Kernel associated with this Console.
|
||||
*/
|
||||
public function getKernel(): KernelInterface
|
||||
{
|
||||
return $this->kernel;
|
||||
}
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
if ($this->kernel->getContainer()->has('services_resetter')) {
|
||||
$this->kernel->getContainer()->get('services_resetter')->reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the current application.
|
||||
*
|
||||
* @return int 0 if everything went fine, or an error code
|
||||
*/
|
||||
public function doRun(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$this->registerCommands();
|
||||
|
||||
if ($this->registrationErrors) {
|
||||
$this->renderRegistrationErrors($input, $output);
|
||||
}
|
||||
|
||||
$this->setDispatcher($this->kernel->getContainer()->get('event_dispatcher'));
|
||||
|
||||
return parent::doRun($input, $output);
|
||||
}
|
||||
|
||||
protected function doRunCommand(Command $command, InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$requestStack = null;
|
||||
$renderRegistrationErrors = true;
|
||||
|
||||
if (!$command instanceof ListCommand) {
|
||||
if ($this->registrationErrors) {
|
||||
$this->renderRegistrationErrors($input, $output);
|
||||
$this->registrationErrors = [];
|
||||
$renderRegistrationErrors = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($input->hasParameterOption('--profile')) {
|
||||
$container = $this->kernel->getContainer();
|
||||
|
||||
if (!$this->kernel->isDebug()) {
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
(new SymfonyStyle($input, $output))->warning('Debug mode should be enabled when the "--profile" option is used.');
|
||||
} elseif (!$container->has('debug.stopwatch')) {
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
(new SymfonyStyle($input, $output))->warning('The "--profile" option needs the Stopwatch component. Try running "composer require symfony/stopwatch".');
|
||||
} elseif (!$container->has('.virtual_request_stack')) {
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
(new SymfonyStyle($input, $output))->warning('The "--profile" option needs the profiler integration. Try enabling the "framework.profiler" option.');
|
||||
} else {
|
||||
$command = new TraceableCommand($command, $container->get('debug.stopwatch'));
|
||||
|
||||
$requestStack = $container->get('.virtual_request_stack');
|
||||
$requestStack->push(new CliRequest($command));
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$returnCode = parent::doRunCommand($command, $input, $output);
|
||||
} finally {
|
||||
$requestStack?->pop();
|
||||
}
|
||||
|
||||
if ($renderRegistrationErrors && $this->registrationErrors) {
|
||||
$this->renderRegistrationErrors($input, $output);
|
||||
$this->registrationErrors = [];
|
||||
}
|
||||
|
||||
return $returnCode;
|
||||
}
|
||||
|
||||
public function find(string $name): Command
|
||||
{
|
||||
$this->registerCommands();
|
||||
|
||||
return parent::find($name);
|
||||
}
|
||||
|
||||
public function get(string $name): Command
|
||||
{
|
||||
$this->registerCommands();
|
||||
|
||||
return parent::get($name);
|
||||
}
|
||||
|
||||
public function all(?string $namespace = null): array
|
||||
{
|
||||
$this->registerCommands();
|
||||
|
||||
return parent::all($namespace);
|
||||
}
|
||||
|
||||
public function getLongVersion(): string
|
||||
{
|
||||
return parent::getLongVersion().\sprintf(' (env: <comment>%s</>, debug: <comment>%s</>)', $this->kernel->getEnvironment(), $this->kernel->isDebug() ? 'true' : 'false');
|
||||
}
|
||||
|
||||
public function add(Command $command): ?Command
|
||||
{
|
||||
$this->registerCommands();
|
||||
|
||||
return parent::add($command);
|
||||
}
|
||||
|
||||
protected function registerCommands(): void
|
||||
{
|
||||
if ($this->commandsRegistered) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->commandsRegistered = true;
|
||||
|
||||
$this->kernel->boot();
|
||||
|
||||
$container = $this->kernel->getContainer();
|
||||
|
||||
foreach ($this->kernel->getBundles() as $bundle) {
|
||||
if ($bundle instanceof Bundle) {
|
||||
try {
|
||||
$bundle->registerCommands($this);
|
||||
} catch (\Throwable $e) {
|
||||
$this->registrationErrors[] = $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($container->has('console.command_loader')) {
|
||||
$this->setCommandLoader($container->get('console.command_loader'));
|
||||
}
|
||||
|
||||
if ($container->hasParameter('console.command.ids')) {
|
||||
$lazyCommandIds = $container->hasParameter('console.lazy_command.ids') ? $container->getParameter('console.lazy_command.ids') : [];
|
||||
foreach ($container->getParameter('console.command.ids') as $id) {
|
||||
if (!isset($lazyCommandIds[$id])) {
|
||||
try {
|
||||
$this->add($container->get($id));
|
||||
} catch (\Throwable $e) {
|
||||
$this->registrationErrors[] = $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function renderRegistrationErrors(InputInterface $input, OutputInterface $output): void
|
||||
{
|
||||
if ($output instanceof ConsoleOutputInterface) {
|
||||
$output = $output->getErrorOutput();
|
||||
}
|
||||
|
||||
(new SymfonyStyle($input, $output))->warning('Some commands could not be registered:');
|
||||
|
||||
foreach ($this->registrationErrors as $error) {
|
||||
$this->doRenderThrowable($error, $output);
|
||||
}
|
||||
}
|
||||
}
|
||||
379
vendor/symfony/framework-bundle/Console/Descriptor/Descriptor.php
vendored
Normal file
379
vendor/symfony/framework-bundle/Console/Descriptor/Descriptor.php
vendored
Normal file
@@ -0,0 +1,379 @@
|
||||
<?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\Bundle\FrameworkBundle\Console\Descriptor;
|
||||
|
||||
use Symfony\Component\Config\Resource\ClassExistenceResource;
|
||||
use Symfony\Component\Console\Descriptor\DescriptorInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceReferenceGraphEdge;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
abstract class Descriptor implements DescriptorInterface
|
||||
{
|
||||
protected OutputInterface $output;
|
||||
|
||||
public function describe(OutputInterface $output, mixed $object, array $options = []): void
|
||||
{
|
||||
$this->output = $output;
|
||||
|
||||
if ($object instanceof ContainerBuilder) {
|
||||
(new AnalyzeServiceReferencesPass(false, false))->process($object);
|
||||
}
|
||||
|
||||
$deprecatedParameters = [];
|
||||
if ($object instanceof ContainerBuilder && isset($options['parameter']) && ($parameterBag = $object->getParameterBag()) instanceof ParameterBag) {
|
||||
$deprecatedParameters = $parameterBag->allDeprecated();
|
||||
}
|
||||
|
||||
match (true) {
|
||||
$object instanceof RouteCollection => $this->describeRouteCollection($this->filterRoutesByHttpMethod($object, $options['method'] ?? ''), $options),
|
||||
$object instanceof Route => $this->describeRoute($object, $options),
|
||||
$object instanceof ParameterBag => $this->describeContainerParameters($object, $options),
|
||||
$object instanceof ContainerBuilder && !empty($options['env-vars']) => $this->describeContainerEnvVars($this->getContainerEnvVars($object), $options),
|
||||
$object instanceof ContainerBuilder && isset($options['group_by']) && 'tags' === $options['group_by'] => $this->describeContainerTags($object, $options),
|
||||
$object instanceof ContainerBuilder && isset($options['id']) => $this->describeContainerService($this->resolveServiceDefinition($object, $options['id']), $options, $object),
|
||||
$object instanceof ContainerBuilder && isset($options['parameter']) => $this->describeContainerParameter($object->resolveEnvPlaceholders($object->getParameter($options['parameter'])), $deprecatedParameters[$options['parameter']] ?? null, $options),
|
||||
$object instanceof ContainerBuilder && isset($options['deprecations']) => $this->describeContainerDeprecations($object, $options),
|
||||
$object instanceof ContainerBuilder => $this->describeContainerServices($object, $options),
|
||||
$object instanceof Definition => $this->describeContainerDefinition($object, $options),
|
||||
$object instanceof Alias => $this->describeContainerAlias($object, $options),
|
||||
$object instanceof EventDispatcherInterface => $this->describeEventDispatcherListeners($object, $options),
|
||||
\is_callable($object) => $this->describeCallable($object, $options),
|
||||
default => throw new \InvalidArgumentException(\sprintf('Object of type "%s" is not describable.', get_debug_type($object))),
|
||||
};
|
||||
|
||||
if ($object instanceof ContainerBuilder) {
|
||||
$object->getCompiler()->getServiceReferenceGraph()->clear();
|
||||
}
|
||||
}
|
||||
|
||||
protected function getOutput(): OutputInterface
|
||||
{
|
||||
return $this->output;
|
||||
}
|
||||
|
||||
protected function write(string $content, bool $decorated = false): void
|
||||
{
|
||||
$this->output->write($content, false, $decorated ? OutputInterface::OUTPUT_NORMAL : OutputInterface::OUTPUT_RAW);
|
||||
}
|
||||
|
||||
abstract protected function describeRouteCollection(RouteCollection $routes, array $options = []): void;
|
||||
|
||||
abstract protected function describeRoute(Route $route, array $options = []): void;
|
||||
|
||||
abstract protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void;
|
||||
|
||||
abstract protected function describeContainerTags(ContainerBuilder $container, array $options = []): void;
|
||||
|
||||
/**
|
||||
* Describes a container service by its name.
|
||||
*
|
||||
* Common options are:
|
||||
* * name: name of described service
|
||||
*
|
||||
* @param Definition|Alias|object $service
|
||||
*/
|
||||
abstract protected function describeContainerService(object $service, array $options = [], ?ContainerBuilder $container = null): void;
|
||||
|
||||
/**
|
||||
* Describes container services.
|
||||
*
|
||||
* Common options are:
|
||||
* * tag: filters described services by given tag
|
||||
*/
|
||||
abstract protected function describeContainerServices(ContainerBuilder $container, array $options = []): void;
|
||||
|
||||
abstract protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void;
|
||||
|
||||
abstract protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void;
|
||||
|
||||
abstract protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void;
|
||||
|
||||
abstract protected function describeContainerParameter(mixed $parameter, ?array $deprecation, array $options = []): void;
|
||||
|
||||
abstract protected function describeContainerEnvVars(array $envs, array $options = []): void;
|
||||
|
||||
/**
|
||||
* Describes event dispatcher listeners.
|
||||
*
|
||||
* Common options are:
|
||||
* * name: name of listened event
|
||||
*/
|
||||
abstract protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []): void;
|
||||
|
||||
abstract protected function describeCallable(mixed $callable, array $options = []): void;
|
||||
|
||||
protected function formatValue(mixed $value): string
|
||||
{
|
||||
if ($value instanceof \UnitEnum) {
|
||||
return ltrim(var_export($value, true), '\\');
|
||||
}
|
||||
|
||||
if (\is_object($value)) {
|
||||
return \sprintf('object(%s)', $value::class);
|
||||
}
|
||||
|
||||
if (\is_string($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return preg_replace("/\n\s*/s", '', var_export($value, true));
|
||||
}
|
||||
|
||||
protected function formatParameter(mixed $value): string
|
||||
{
|
||||
if ($value instanceof \UnitEnum) {
|
||||
return ltrim(var_export($value, true), '\\');
|
||||
}
|
||||
|
||||
// Recursively search for enum values, so we can replace it
|
||||
// before json_encode (which will not display anything for \UnitEnum otherwise)
|
||||
if (\is_array($value)) {
|
||||
array_walk_recursive($value, static function (&$value) {
|
||||
if ($value instanceof \UnitEnum) {
|
||||
$value = ltrim(var_export($value, true), '\\');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (\is_bool($value) || \is_array($value) || (null === $value)) {
|
||||
$jsonString = json_encode($value);
|
||||
|
||||
if (preg_match('/^(.{60})./us', $jsonString, $matches)) {
|
||||
return $matches[1].'...';
|
||||
}
|
||||
|
||||
return $jsonString;
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
protected function resolveServiceDefinition(ContainerBuilder $container, string $serviceId): mixed
|
||||
{
|
||||
if ($container->hasDefinition($serviceId)) {
|
||||
return $container->getDefinition($serviceId);
|
||||
}
|
||||
|
||||
// Some service IDs don't have a Definition, they're aliases
|
||||
if ($container->hasAlias($serviceId)) {
|
||||
return $container->getAlias($serviceId);
|
||||
}
|
||||
|
||||
if ('service_container' === $serviceId) {
|
||||
return (new Definition(ContainerInterface::class))->setPublic(true)->setSynthetic(true);
|
||||
}
|
||||
|
||||
// the service has been injected in some special way, just return the service
|
||||
return $container->get($serviceId);
|
||||
}
|
||||
|
||||
protected function findDefinitionsByTag(ContainerBuilder $container, bool $showHidden): array
|
||||
{
|
||||
$definitions = [];
|
||||
$tags = $container->findTags();
|
||||
asort($tags);
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
foreach ($container->findTaggedServiceIds($tag) as $serviceId => $attributes) {
|
||||
$definition = $this->resolveServiceDefinition($container, $serviceId);
|
||||
|
||||
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($definitions[$tag])) {
|
||||
$definitions[$tag] = [];
|
||||
}
|
||||
|
||||
$definitions[$tag][$serviceId] = $definition;
|
||||
}
|
||||
}
|
||||
|
||||
return $definitions;
|
||||
}
|
||||
|
||||
protected function sortParameters(ParameterBag $parameters): array
|
||||
{
|
||||
$parameters = $parameters->all();
|
||||
ksort($parameters);
|
||||
|
||||
return $parameters;
|
||||
}
|
||||
|
||||
protected function sortServiceIds(array $serviceIds): array
|
||||
{
|
||||
asort($serviceIds);
|
||||
|
||||
return $serviceIds;
|
||||
}
|
||||
|
||||
protected function sortTaggedServicesByPriority(array $services): array
|
||||
{
|
||||
$maxPriority = [];
|
||||
foreach ($services as $service => $tags) {
|
||||
$maxPriority[$service] = \PHP_INT_MIN;
|
||||
foreach ($tags as $tag) {
|
||||
$currentPriority = $tag['priority'] ?? 0;
|
||||
if ($maxPriority[$service] < $currentPriority) {
|
||||
$maxPriority[$service] = $currentPriority;
|
||||
}
|
||||
}
|
||||
}
|
||||
uasort($maxPriority, fn ($a, $b) => $b <=> $a);
|
||||
|
||||
return array_keys($maxPriority);
|
||||
}
|
||||
|
||||
protected function sortTagsByPriority(array $tags): array
|
||||
{
|
||||
$sortedTags = [];
|
||||
foreach ($tags as $tagName => $tag) {
|
||||
$sortedTags[$tagName] = $this->sortByPriority($tag);
|
||||
}
|
||||
|
||||
return $sortedTags;
|
||||
}
|
||||
|
||||
protected function sortByPriority(array $tag): array
|
||||
{
|
||||
usort($tag, fn ($a, $b) => ($b['priority'] ?? 0) <=> ($a['priority'] ?? 0));
|
||||
|
||||
return $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string[]>
|
||||
*/
|
||||
protected function getReverseAliases(RouteCollection $routes): array
|
||||
{
|
||||
$reverseAliases = [];
|
||||
foreach ($routes->getAliases() as $name => $alias) {
|
||||
$reverseAliases[$alias->getId()][] = $name;
|
||||
}
|
||||
|
||||
return $reverseAliases;
|
||||
}
|
||||
|
||||
public static function getClassDescription(string $class, ?string &$resolvedClass = null): string
|
||||
{
|
||||
$resolvedClass = $class;
|
||||
try {
|
||||
$resource = new ClassExistenceResource($class, false);
|
||||
|
||||
// isFresh() will explode ONLY if a parent class/trait does not exist
|
||||
$resource->isFresh(0);
|
||||
|
||||
$r = new \ReflectionClass($class);
|
||||
$resolvedClass = $r->name;
|
||||
|
||||
if ($docComment = $r->getDocComment()) {
|
||||
$docComment = preg_split('#\n\s*\*\s*[\n@]#', substr($docComment, 3, -2), 2)[0];
|
||||
|
||||
return trim(preg_replace('#\s*\n\s*\*\s*#', ' ', $docComment));
|
||||
}
|
||||
} catch (\ReflectionException) {
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function getContainerEnvVars(ContainerBuilder $container): array
|
||||
{
|
||||
if (!$container->hasParameter('debug.container.dump')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$container->getParameter('debug.container.dump') || !is_file($container->getParameter('debug.container.dump'))) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$file = file_get_contents($container->getParameter('debug.container.dump'));
|
||||
preg_match_all('{%env\(((?:\w++:)*+\w++)\)%}', $file, $envVars);
|
||||
$envVars = array_unique($envVars[1]);
|
||||
|
||||
$bag = $container->getParameterBag();
|
||||
$getDefaultParameter = fn (string $name) => parent::get($name);
|
||||
$getDefaultParameter = $getDefaultParameter->bindTo($bag, $bag::class);
|
||||
|
||||
$getEnvReflection = new \ReflectionMethod($container, 'getEnv');
|
||||
|
||||
$envs = [];
|
||||
|
||||
foreach ($envVars as $env) {
|
||||
$processor = 'string';
|
||||
if (false !== $i = strrpos($name = $env, ':')) {
|
||||
$name = substr($env, $i + 1);
|
||||
$processor = substr($env, 0, $i);
|
||||
}
|
||||
$defaultValue = ($hasDefault = $container->hasParameter("env($name)")) ? $getDefaultParameter("env($name)") : null;
|
||||
if (false === ($runtimeValue = $_ENV[$name] ?? $_SERVER[$name] ?? getenv($name))) {
|
||||
$runtimeValue = null;
|
||||
}
|
||||
$processedValue = ($hasRuntime = null !== $runtimeValue) || $hasDefault ? $getEnvReflection->invoke($container, $env) : null;
|
||||
$envs["$name$processor"] = [
|
||||
'name' => $name,
|
||||
'processor' => $processor,
|
||||
'default_available' => $hasDefault,
|
||||
'default_value' => $defaultValue,
|
||||
'runtime_available' => $hasRuntime,
|
||||
'runtime_value' => $runtimeValue,
|
||||
'processed_value' => $processedValue,
|
||||
];
|
||||
}
|
||||
ksort($envs);
|
||||
|
||||
return array_values($envs);
|
||||
}
|
||||
|
||||
protected function getServiceEdges(ContainerBuilder $container, string $serviceId): array
|
||||
{
|
||||
try {
|
||||
return array_values(array_unique(array_map(
|
||||
fn (ServiceReferenceGraphEdge $edge) => $edge->getSourceNode()->getId(),
|
||||
$container->getCompiler()->getServiceReferenceGraph()->getNode($serviceId)->getInEdges()
|
||||
)));
|
||||
} catch (InvalidArgumentException $exception) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private function filterRoutesByHttpMethod(RouteCollection $routes, string $method): RouteCollection
|
||||
{
|
||||
if (!$method) {
|
||||
return $routes;
|
||||
}
|
||||
$filteredRoutes = clone $routes;
|
||||
|
||||
foreach ($filteredRoutes as $routeName => $route) {
|
||||
if ($route->getMethods() && !\in_array($method, $route->getMethods(), true)) {
|
||||
$filteredRoutes->remove($routeName);
|
||||
}
|
||||
}
|
||||
|
||||
return $filteredRoutes;
|
||||
}
|
||||
}
|
||||
454
vendor/symfony/framework-bundle/Console/Descriptor/JsonDescriptor.php
vendored
Normal file
454
vendor/symfony/framework-bundle/Console/Descriptor/JsonDescriptor.php
vendored
Normal file
@@ -0,0 +1,454 @@
|
||||
<?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\Bundle\FrameworkBundle\Console\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class JsonDescriptor extends Descriptor
|
||||
{
|
||||
protected function describeRouteCollection(RouteCollection $routes, array $options = []): void
|
||||
{
|
||||
$data = [];
|
||||
foreach ($routes->all() as $name => $route) {
|
||||
$data[$name] = $this->getRouteData($route);
|
||||
if (($showAliases ??= $options['show_aliases'] ?? false) && $aliases = ($reverseAliases ??= $this->getReverseAliases($routes))[$name] ?? []) {
|
||||
$data[$name]['aliases'] = $aliases;
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeData($data, $options);
|
||||
}
|
||||
|
||||
protected function describeRoute(Route $route, array $options = []): void
|
||||
{
|
||||
$this->writeData($this->getRouteData($route), $options);
|
||||
}
|
||||
|
||||
protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void
|
||||
{
|
||||
$this->writeData($this->sortParameters($parameters), $options);
|
||||
}
|
||||
|
||||
protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
|
||||
$data = [];
|
||||
|
||||
foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
|
||||
$data[$tag] = [];
|
||||
foreach ($definitions as $definition) {
|
||||
$data[$tag][] = $this->getContainerDefinitionData($definition, true, $container, $options['id'] ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeData($data, $options);
|
||||
}
|
||||
|
||||
protected function describeContainerService(object $service, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
if (!isset($options['id'])) {
|
||||
throw new \InvalidArgumentException('An "id" option must be provided.');
|
||||
}
|
||||
|
||||
if ($service instanceof Alias) {
|
||||
$this->describeContainerAlias($service, $options, $container);
|
||||
} elseif ($service instanceof Definition) {
|
||||
$this->writeData($this->getContainerDefinitionData($service, isset($options['omit_tags']) && $options['omit_tags'], $container, $options['id']), $options);
|
||||
} else {
|
||||
$this->writeData($service::class, $options);
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$serviceIds = isset($options['tag']) && $options['tag']
|
||||
? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($options['tag']))
|
||||
: $this->sortServiceIds($container->getServiceIds());
|
||||
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
|
||||
$omitTags = isset($options['omit_tags']) && $options['omit_tags'];
|
||||
$data = ['definitions' => [], 'aliases' => [], 'services' => []];
|
||||
|
||||
if (isset($options['filter'])) {
|
||||
$serviceIds = array_filter($serviceIds, $options['filter']);
|
||||
}
|
||||
|
||||
foreach ($serviceIds as $serviceId) {
|
||||
$service = $this->resolveServiceDefinition($container, $serviceId);
|
||||
|
||||
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($service instanceof Alias) {
|
||||
$data['aliases'][$serviceId] = $this->getContainerAliasData($service);
|
||||
} elseif ($service instanceof Definition) {
|
||||
if ($service->hasTag('container.excluded')) {
|
||||
continue;
|
||||
}
|
||||
$data['definitions'][$serviceId] = $this->getContainerDefinitionData($service, $omitTags, $container, $serviceId);
|
||||
} else {
|
||||
$data['services'][$serviceId] = $service::class;
|
||||
}
|
||||
}
|
||||
|
||||
$this->writeData($data, $options);
|
||||
}
|
||||
|
||||
protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
$this->writeData($this->getContainerDefinitionData($definition, isset($options['omit_tags']) && $options['omit_tags'], $container, $options['id'] ?? null), $options);
|
||||
}
|
||||
|
||||
protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
if (!$container) {
|
||||
$this->writeData($this->getContainerAliasData($alias), $options);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->writeData(
|
||||
[$this->getContainerAliasData($alias), $this->getContainerDefinitionData($container->getDefinition((string) $alias), isset($options['omit_tags']) && $options['omit_tags'], $container, (string) $alias)],
|
||||
array_merge($options, ['id' => (string) $alias])
|
||||
);
|
||||
}
|
||||
|
||||
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []): void
|
||||
{
|
||||
$this->writeData($this->getEventDispatcherListenersData($eventDispatcher, $options), $options);
|
||||
}
|
||||
|
||||
protected function describeCallable(mixed $callable, array $options = []): void
|
||||
{
|
||||
$this->writeData($this->getCallableData($callable), $options);
|
||||
}
|
||||
|
||||
protected function describeContainerParameter(mixed $parameter, ?array $deprecation, array $options = []): void
|
||||
{
|
||||
$key = $options['parameter'] ?? '';
|
||||
$data = [$key => $parameter];
|
||||
|
||||
if ($deprecation) {
|
||||
$data['_deprecation'] = \sprintf('Since %s %s: %s', $deprecation[0], $deprecation[1], \sprintf(...\array_slice($deprecation, 2)));
|
||||
}
|
||||
|
||||
$this->writeData($data, $options);
|
||||
}
|
||||
|
||||
protected function describeContainerEnvVars(array $envs, array $options = []): void
|
||||
{
|
||||
throw new LogicException('Using the JSON format to debug environment variables is not supported.');
|
||||
}
|
||||
|
||||
protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$containerDeprecationFilePath = \sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
|
||||
if (!file_exists($containerDeprecationFilePath)) {
|
||||
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
|
||||
}
|
||||
|
||||
$logs = unserialize(file_get_contents($containerDeprecationFilePath));
|
||||
|
||||
$formattedLogs = [];
|
||||
$remainingCount = 0;
|
||||
foreach ($logs as $log) {
|
||||
$formattedLogs[] = [
|
||||
'message' => $log['message'],
|
||||
'file' => $log['file'],
|
||||
'line' => $log['line'],
|
||||
'count' => $log['count'],
|
||||
];
|
||||
$remainingCount += $log['count'];
|
||||
}
|
||||
|
||||
$this->writeData(['remainingCount' => $remainingCount, 'deprecations' => $formattedLogs], $options);
|
||||
}
|
||||
|
||||
private function writeData(array $data, array $options): void
|
||||
{
|
||||
$flags = $options['json_encoding'] ?? 0;
|
||||
|
||||
// Recursively search for enum values, so we can replace it
|
||||
// before json_encode (which will not display anything for \UnitEnum otherwise)
|
||||
array_walk_recursive($data, static function (&$value) {
|
||||
if ($value instanceof \UnitEnum) {
|
||||
$value = ltrim(var_export($value, true), '\\');
|
||||
}
|
||||
});
|
||||
|
||||
$this->write(json_encode($data, $flags | \JSON_PRETTY_PRINT)."\n");
|
||||
}
|
||||
|
||||
protected function getRouteData(Route $route): array
|
||||
{
|
||||
$data = [
|
||||
'path' => $route->getPath(),
|
||||
'pathRegex' => $route->compile()->getRegex(),
|
||||
'host' => '' !== $route->getHost() ? $route->getHost() : 'ANY',
|
||||
'hostRegex' => '' !== $route->getHost() ? $route->compile()->getHostRegex() : '',
|
||||
'scheme' => $route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY',
|
||||
'method' => $route->getMethods() ? implode('|', $route->getMethods()) : 'ANY',
|
||||
'class' => $route::class,
|
||||
'defaults' => $route->getDefaults(),
|
||||
'requirements' => $route->getRequirements() ?: 'NO CUSTOM',
|
||||
'options' => $route->getOptions(),
|
||||
];
|
||||
|
||||
if ('' !== $route->getCondition()) {
|
||||
$data['condition'] = $route->getCondition();
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function sortParameters(ParameterBag $parameters): array
|
||||
{
|
||||
$sortedParameters = parent::sortParameters($parameters);
|
||||
|
||||
if ($deprecated = $parameters->allDeprecated()) {
|
||||
$deprecations = [];
|
||||
|
||||
foreach ($deprecated as $parameter => $deprecation) {
|
||||
$deprecations[$parameter] = \sprintf('Since %s %s: %s', $deprecation[0], $deprecation[1], \sprintf(...\array_slice($deprecation, 2)));
|
||||
}
|
||||
|
||||
$sortedParameters['_deprecations'] = $deprecations;
|
||||
}
|
||||
|
||||
return $sortedParameters;
|
||||
}
|
||||
|
||||
private function getContainerDefinitionData(Definition $definition, bool $omitTags = false, ?ContainerBuilder $container = null, ?string $id = null): array
|
||||
{
|
||||
$data = [
|
||||
'class' => (string) $definition->getClass(),
|
||||
'public' => $definition->isPublic() && !$definition->isPrivate(),
|
||||
'synthetic' => $definition->isSynthetic(),
|
||||
'lazy' => $definition->isLazy(),
|
||||
'shared' => $definition->isShared(),
|
||||
'abstract' => $definition->isAbstract(),
|
||||
'autowire' => $definition->isAutowired(),
|
||||
'autoconfigure' => $definition->isAutoconfigured(),
|
||||
];
|
||||
|
||||
if ($definition->isDeprecated()) {
|
||||
$data['deprecated'] = true;
|
||||
$data['deprecation_message'] = $definition->getDeprecation($id)['message'];
|
||||
} else {
|
||||
$data['deprecated'] = false;
|
||||
}
|
||||
|
||||
if ('' !== $classDescription = $this->getClassDescription((string) $definition->getClass())) {
|
||||
$data['description'] = $classDescription;
|
||||
}
|
||||
|
||||
$data['arguments'] = $this->describeValue($definition->getArguments(), $omitTags, $container, $id);
|
||||
|
||||
$data['file'] = $definition->getFile();
|
||||
|
||||
if ($factory = $definition->getFactory()) {
|
||||
if (\is_array($factory)) {
|
||||
if ($factory[0] instanceof Reference) {
|
||||
$data['factory_service'] = (string) $factory[0];
|
||||
} elseif ($factory[0] instanceof Definition) {
|
||||
$data['factory_service'] = \sprintf('inline factory service (%s)', $factory[0]->getClass() ?? 'class not configured');
|
||||
} else {
|
||||
$data['factory_class'] = $factory[0];
|
||||
}
|
||||
$data['factory_method'] = $factory[1];
|
||||
} else {
|
||||
$data['factory_function'] = $factory;
|
||||
}
|
||||
}
|
||||
|
||||
$calls = $definition->getMethodCalls();
|
||||
if (\count($calls) > 0) {
|
||||
$data['calls'] = [];
|
||||
foreach ($calls as $callData) {
|
||||
$data['calls'][] = $callData[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$omitTags) {
|
||||
$data['tags'] = [];
|
||||
foreach ($this->sortTagsByPriority($definition->getTags()) as $tagName => $tagData) {
|
||||
foreach ($tagData as $parameters) {
|
||||
$data['tags'][] = ['name' => $tagName, 'parameters' => $parameters];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data['usages'] = null !== $container && null !== $id ? $this->getServiceEdges($container, $id) : [];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function getContainerAliasData(Alias $alias): array
|
||||
{
|
||||
return [
|
||||
'service' => (string) $alias,
|
||||
'public' => $alias->isPublic() && !$alias->isPrivate(),
|
||||
];
|
||||
}
|
||||
|
||||
private function getEventDispatcherListenersData(EventDispatcherInterface $eventDispatcher, array $options): array
|
||||
{
|
||||
$data = [];
|
||||
$event = $options['event'] ?? null;
|
||||
|
||||
if (null !== $event) {
|
||||
foreach ($eventDispatcher->getListeners($event) as $listener) {
|
||||
$l = $this->getCallableData($listener);
|
||||
$l['priority'] = $eventDispatcher->getListenerPriority($event, $listener);
|
||||
$data[] = $l;
|
||||
}
|
||||
} else {
|
||||
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(fn ($event) => $eventDispatcher->getListeners($event), $options['events'])) : $eventDispatcher->getListeners();
|
||||
ksort($registeredListeners);
|
||||
|
||||
foreach ($registeredListeners as $eventListened => $eventListeners) {
|
||||
foreach ($eventListeners as $eventListener) {
|
||||
$l = $this->getCallableData($eventListener);
|
||||
$l['priority'] = $eventDispatcher->getListenerPriority($eventListened, $eventListener);
|
||||
$data[$eventListened][] = $l;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function getCallableData(mixed $callable): array
|
||||
{
|
||||
$data = [];
|
||||
|
||||
if (\is_array($callable)) {
|
||||
$data['type'] = 'function';
|
||||
|
||||
if (\is_object($callable[0])) {
|
||||
$data['name'] = $callable[1];
|
||||
$data['class'] = $callable[0]::class;
|
||||
} else {
|
||||
if (!str_starts_with($callable[1], 'parent::')) {
|
||||
$data['name'] = $callable[1];
|
||||
$data['class'] = $callable[0];
|
||||
$data['static'] = true;
|
||||
} else {
|
||||
$data['name'] = substr($callable[1], 8);
|
||||
$data['class'] = $callable[0];
|
||||
$data['static'] = true;
|
||||
$data['parent'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
if (\is_string($callable)) {
|
||||
$data['type'] = 'function';
|
||||
|
||||
if (!str_contains($callable, '::')) {
|
||||
$data['name'] = $callable;
|
||||
} else {
|
||||
$callableParts = explode('::', $callable);
|
||||
|
||||
$data['name'] = $callableParts[1];
|
||||
$data['class'] = $callableParts[0];
|
||||
$data['static'] = true;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ($callable instanceof \Closure) {
|
||||
$data['type'] = 'closure';
|
||||
|
||||
$r = new \ReflectionFunction($callable);
|
||||
if ($r->isAnonymous()) {
|
||||
return $data;
|
||||
}
|
||||
$data['name'] = $r->name;
|
||||
|
||||
if ($class = $r->getClosureCalledClass()) {
|
||||
$data['class'] = $class->name;
|
||||
if (!$r->getClosureThis()) {
|
||||
$data['static'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
if (method_exists($callable, '__invoke')) {
|
||||
$data['type'] = 'object';
|
||||
$data['name'] = $callable::class;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Callable is not describable.');
|
||||
}
|
||||
|
||||
private function describeValue($value, bool $omitTags, ?ContainerBuilder $container = null, ?string $id = null): mixed
|
||||
{
|
||||
if (\is_array($value)) {
|
||||
$data = [];
|
||||
foreach ($value as $k => $v) {
|
||||
$data[$k] = $this->describeValue($v, $omitTags, $container, $id);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ($value instanceof ServiceClosureArgument) {
|
||||
$value = $value->getValues()[0];
|
||||
}
|
||||
|
||||
if ($value instanceof Reference) {
|
||||
return [
|
||||
'type' => 'service',
|
||||
'id' => (string) $value,
|
||||
];
|
||||
}
|
||||
|
||||
if ($value instanceof AbstractArgument) {
|
||||
return ['type' => 'abstract', 'text' => $value->getText()];
|
||||
}
|
||||
|
||||
if ($value instanceof ArgumentInterface) {
|
||||
return $this->describeValue($value->getValues(), $omitTags, $container, $id);
|
||||
}
|
||||
|
||||
if ($value instanceof Definition) {
|
||||
return $this->getContainerDefinitionData($value, $omitTags, $container, $id);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
448
vendor/symfony/framework-bundle/Console/Descriptor/MarkdownDescriptor.php
vendored
Normal file
448
vendor/symfony/framework-bundle/Console/Descriptor/MarkdownDescriptor.php
vendored
Normal file
@@ -0,0 +1,448 @@
|
||||
<?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\Bundle\FrameworkBundle\Console\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class MarkdownDescriptor extends Descriptor
|
||||
{
|
||||
protected function describeRouteCollection(RouteCollection $routes, array $options = []): void
|
||||
{
|
||||
$first = true;
|
||||
foreach ($routes->all() as $name => $route) {
|
||||
if ($first) {
|
||||
$first = false;
|
||||
} else {
|
||||
$this->write("\n\n");
|
||||
}
|
||||
$this->describeRoute($route, ['name' => $name]);
|
||||
if (($showAliases ??= $options['show_aliases'] ?? false) && $aliases = ($reverseAliases ??= $this->getReverseAliases($routes))[$name] ?? []) {
|
||||
$this->write(\sprintf("- Aliases: \n%s", implode("\n", array_map(static fn (string $alias): string => \sprintf(' - %s', $alias), $aliases))));
|
||||
}
|
||||
}
|
||||
$this->write("\n");
|
||||
}
|
||||
|
||||
protected function describeRoute(Route $route, array $options = []): void
|
||||
{
|
||||
$output = '- Path: '.$route->getPath()
|
||||
."\n".'- Path Regex: '.$route->compile()->getRegex()
|
||||
."\n".'- Host: '.('' !== $route->getHost() ? $route->getHost() : 'ANY')
|
||||
."\n".'- Host Regex: '.('' !== $route->getHost() ? $route->compile()->getHostRegex() : '')
|
||||
."\n".'- Scheme: '.($route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY')
|
||||
."\n".'- Method: '.($route->getMethods() ? implode('|', $route->getMethods()) : 'ANY')
|
||||
."\n".'- Class: '.$route::class
|
||||
."\n".'- Defaults: '.$this->formatRouterConfig($route->getDefaults())
|
||||
."\n".'- Requirements: '.($route->getRequirements() ? $this->formatRouterConfig($route->getRequirements()) : 'NO CUSTOM')
|
||||
."\n".'- Options: '.$this->formatRouterConfig($route->getOptions());
|
||||
|
||||
if ('' !== $route->getCondition()) {
|
||||
$output .= "\n".'- Condition: '.$route->getCondition();
|
||||
}
|
||||
|
||||
$this->write(isset($options['name'])
|
||||
? $options['name']."\n".str_repeat('-', \strlen($options['name']))."\n\n".$output
|
||||
: $output);
|
||||
$this->write("\n");
|
||||
}
|
||||
|
||||
protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void
|
||||
{
|
||||
$deprecatedParameters = $parameters->allDeprecated();
|
||||
|
||||
$this->write("Container parameters\n====================\n");
|
||||
foreach ($this->sortParameters($parameters) as $key => $value) {
|
||||
$this->write(\sprintf(
|
||||
"\n- `%s`: `%s`%s",
|
||||
$key,
|
||||
$this->formatParameter($value),
|
||||
isset($deprecatedParameters[$key]) ? \sprintf(' *Since %s %s: %s*', $deprecatedParameters[$key][0], $deprecatedParameters[$key][1], \sprintf(...\array_slice($deprecatedParameters[$key], 2))) : ''
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
|
||||
$this->write("Container tags\n==============");
|
||||
|
||||
foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
|
||||
$this->write("\n\n".$tag."\n".str_repeat('-', \strlen($tag)));
|
||||
foreach ($definitions as $serviceId => $definition) {
|
||||
$this->write("\n\n");
|
||||
$this->describeContainerDefinition($definition, ['omit_tags' => true, 'id' => $serviceId], $container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeContainerService(object $service, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
if (!isset($options['id'])) {
|
||||
throw new \InvalidArgumentException('An "id" option must be provided.');
|
||||
}
|
||||
|
||||
$childOptions = array_merge($options, ['id' => $options['id'], 'as_array' => true]);
|
||||
|
||||
if ($service instanceof Alias) {
|
||||
$this->describeContainerAlias($service, $childOptions, $container);
|
||||
} elseif ($service instanceof Definition) {
|
||||
$this->describeContainerDefinition($service, $childOptions, $container);
|
||||
} else {
|
||||
$this->write(\sprintf('**`%s`:** `%s`', $options['id'], $service::class));
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$containerDeprecationFilePath = \sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
|
||||
if (!file_exists($containerDeprecationFilePath)) {
|
||||
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
|
||||
}
|
||||
|
||||
$logs = unserialize(file_get_contents($containerDeprecationFilePath));
|
||||
if (0 === \count($logs)) {
|
||||
$this->write("## There are no deprecations in the logs!\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$formattedLogs = [];
|
||||
$remainingCount = 0;
|
||||
foreach ($logs as $log) {
|
||||
$formattedLogs[] = \sprintf("- %sx: \"%s\" in %s:%s\n", $log['count'], $log['message'], $log['file'], $log['line']);
|
||||
$remainingCount += $log['count'];
|
||||
}
|
||||
|
||||
$this->write(\sprintf("## Remaining deprecations (%s)\n\n", $remainingCount));
|
||||
foreach ($formattedLogs as $formattedLog) {
|
||||
$this->write($formattedLog);
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
|
||||
|
||||
$title = $showHidden ? 'Hidden services' : 'Services';
|
||||
if (isset($options['tag'])) {
|
||||
$title .= ' with tag `'.$options['tag'].'`';
|
||||
}
|
||||
$this->write($title."\n".str_repeat('=', \strlen($title)));
|
||||
|
||||
$serviceIds = isset($options['tag']) && $options['tag']
|
||||
? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($options['tag']))
|
||||
: $this->sortServiceIds($container->getServiceIds());
|
||||
$services = ['definitions' => [], 'aliases' => [], 'services' => []];
|
||||
|
||||
if (isset($options['filter'])) {
|
||||
$serviceIds = array_filter($serviceIds, $options['filter']);
|
||||
}
|
||||
|
||||
foreach ($serviceIds as $serviceId) {
|
||||
$service = $this->resolveServiceDefinition($container, $serviceId);
|
||||
|
||||
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($service instanceof Alias) {
|
||||
$services['aliases'][$serviceId] = $service;
|
||||
} elseif ($service instanceof Definition) {
|
||||
if ($service->hasTag('container.excluded')) {
|
||||
continue;
|
||||
}
|
||||
$services['definitions'][$serviceId] = $service;
|
||||
} else {
|
||||
$services['services'][$serviceId] = $service;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($services['definitions'])) {
|
||||
$this->write("\n\nDefinitions\n-----------\n");
|
||||
foreach ($services['definitions'] as $id => $service) {
|
||||
$this->write("\n");
|
||||
$this->describeContainerDefinition($service, ['id' => $id], $container);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($services['aliases'])) {
|
||||
$this->write("\n\nAliases\n-------\n");
|
||||
foreach ($services['aliases'] as $id => $service) {
|
||||
$this->write("\n");
|
||||
$this->describeContainerAlias($service, ['id' => $id]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($services['services'])) {
|
||||
$this->write("\n\nServices\n--------\n");
|
||||
foreach ($services['services'] as $id => $service) {
|
||||
$this->write("\n");
|
||||
$this->write(\sprintf('- `%s`: `%s`', $id, $service::class));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
$output = '';
|
||||
|
||||
if ('' !== $classDescription = $this->getClassDescription((string) $definition->getClass())) {
|
||||
$output .= '- Description: `'.$classDescription.'`'."\n";
|
||||
}
|
||||
|
||||
$output .= '- Class: `'.$definition->getClass().'`'
|
||||
."\n".'- Public: '.($definition->isPublic() && !$definition->isPrivate() ? 'yes' : 'no')
|
||||
."\n".'- Synthetic: '.($definition->isSynthetic() ? 'yes' : 'no')
|
||||
."\n".'- Lazy: '.($definition->isLazy() ? 'yes' : 'no')
|
||||
."\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no')
|
||||
."\n".'- Abstract: '.($definition->isAbstract() ? 'yes' : 'no')
|
||||
."\n".'- Autowired: '.($definition->isAutowired() ? 'yes' : 'no')
|
||||
."\n".'- Autoconfigured: '.($definition->isAutoconfigured() ? 'yes' : 'no')
|
||||
;
|
||||
|
||||
if ($definition->isDeprecated()) {
|
||||
$output .= "\n".'- Deprecated: yes';
|
||||
$output .= "\n".'- Deprecation message: '.$definition->getDeprecation($options['id'])['message'];
|
||||
} else {
|
||||
$output .= "\n".'- Deprecated: no';
|
||||
}
|
||||
|
||||
$output .= "\n".'- Arguments: '.($definition->getArguments() ? 'yes' : 'no');
|
||||
|
||||
if ($definition->getFile()) {
|
||||
$output .= "\n".'- File: `'.$definition->getFile().'`';
|
||||
}
|
||||
|
||||
if ($factory = $definition->getFactory()) {
|
||||
if (\is_array($factory)) {
|
||||
if ($factory[0] instanceof Reference) {
|
||||
$output .= "\n".'- Factory Service: `'.$factory[0].'`';
|
||||
} elseif ($factory[0] instanceof Definition) {
|
||||
$output .= "\n".\sprintf('- Factory Service: inline factory service (%s)', $factory[0]->getClass() ? \sprintf('`%s`', $factory[0]->getClass()) : 'not configured');
|
||||
} else {
|
||||
$output .= "\n".'- Factory Class: `'.$factory[0].'`';
|
||||
}
|
||||
$output .= "\n".'- Factory Method: `'.$factory[1].'`';
|
||||
} else {
|
||||
$output .= "\n".'- Factory Function: `'.$factory.'`';
|
||||
}
|
||||
}
|
||||
|
||||
$calls = $definition->getMethodCalls();
|
||||
foreach ($calls as $callData) {
|
||||
$output .= "\n".'- Call: `'.$callData[0].'`';
|
||||
}
|
||||
|
||||
if (!(isset($options['omit_tags']) && $options['omit_tags'])) {
|
||||
foreach ($this->sortTagsByPriority($definition->getTags()) as $tagName => $tagData) {
|
||||
foreach ($tagData as $parameters) {
|
||||
$output .= "\n".'- Tag: `'.$tagName.'`';
|
||||
foreach ($parameters as $name => $value) {
|
||||
$output .= "\n".' - '.ucfirst($name).': '.(\is_array($value) ? $this->formatParameter($value) : $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$inEdges = null !== $container && isset($options['id']) ? $this->getServiceEdges($container, $options['id']) : [];
|
||||
$output .= "\n".'- Usages: '.($inEdges ? implode(', ', $inEdges) : 'none');
|
||||
|
||||
$this->write(isset($options['id']) ? \sprintf("### %s\n\n%s\n", $options['id'], $output) : $output);
|
||||
}
|
||||
|
||||
protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
$output = '- Service: `'.$alias.'`'
|
||||
."\n".'- Public: '.($alias->isPublic() && !$alias->isPrivate() ? 'yes' : 'no');
|
||||
|
||||
if (!isset($options['id'])) {
|
||||
$this->write($output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->write(\sprintf("### %s\n\n%s\n", $options['id'], $output));
|
||||
|
||||
if (!$container) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->write("\n");
|
||||
$this->describeContainerDefinition($container->getDefinition((string) $alias), array_merge($options, ['id' => (string) $alias]), $container);
|
||||
}
|
||||
|
||||
protected function describeContainerParameter(mixed $parameter, ?array $deprecation, array $options = []): void
|
||||
{
|
||||
if (isset($options['parameter'])) {
|
||||
$this->write(\sprintf("%s\n%s\n\n%s%s", $options['parameter'], str_repeat('=', \strlen($options['parameter'])), $this->formatParameter($parameter), $deprecation ? \sprintf("\n\n*Since %s %s: %s*", $deprecation[0], $deprecation[1], \sprintf(...\array_slice($deprecation, 2))) : ''));
|
||||
} else {
|
||||
$this->write($parameter);
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeContainerEnvVars(array $envs, array $options = []): void
|
||||
{
|
||||
throw new LogicException('Using the markdown format to debug environment variables is not supported.');
|
||||
}
|
||||
|
||||
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []): void
|
||||
{
|
||||
$event = $options['event'] ?? null;
|
||||
$dispatcherServiceName = $options['dispatcher_service_name'] ?? null;
|
||||
|
||||
$title = 'Registered listeners';
|
||||
|
||||
if (null !== $dispatcherServiceName) {
|
||||
$title .= \sprintf(' of event dispatcher "%s"', $dispatcherServiceName);
|
||||
}
|
||||
|
||||
if (null !== $event) {
|
||||
$title .= \sprintf(' for event `%s` ordered by descending priority', $event);
|
||||
$registeredListeners = $eventDispatcher->getListeners($event);
|
||||
} else {
|
||||
// Try to see if "events" exists
|
||||
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(fn ($event) => $eventDispatcher->getListeners($event), $options['events'])) : $eventDispatcher->getListeners();
|
||||
}
|
||||
|
||||
$this->write(\sprintf('# %s', $title)."\n");
|
||||
|
||||
if (null !== $event) {
|
||||
foreach ($registeredListeners as $order => $listener) {
|
||||
$this->write("\n".\sprintf('## Listener %d', $order + 1)."\n");
|
||||
$this->describeCallable($listener);
|
||||
$this->write(\sprintf('- Priority: `%d`', $eventDispatcher->getListenerPriority($event, $listener))."\n");
|
||||
}
|
||||
} else {
|
||||
ksort($registeredListeners);
|
||||
|
||||
foreach ($registeredListeners as $eventListened => $eventListeners) {
|
||||
$this->write("\n".\sprintf('## %s', $eventListened)."\n");
|
||||
|
||||
foreach ($eventListeners as $order => $eventListener) {
|
||||
$this->write("\n".\sprintf('### Listener %d', $order + 1)."\n");
|
||||
$this->describeCallable($eventListener);
|
||||
$this->write(\sprintf('- Priority: `%d`', $eventDispatcher->getListenerPriority($eventListened, $eventListener))."\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeCallable(mixed $callable, array $options = []): void
|
||||
{
|
||||
$string = '';
|
||||
|
||||
if (\is_array($callable)) {
|
||||
$string .= "\n- Type: `function`";
|
||||
|
||||
if (\is_object($callable[0])) {
|
||||
$string .= "\n".\sprintf('- Name: `%s`', $callable[1]);
|
||||
$string .= "\n".\sprintf('- Class: `%s`', $callable[0]::class);
|
||||
} else {
|
||||
if (!str_starts_with($callable[1], 'parent::')) {
|
||||
$string .= "\n".\sprintf('- Name: `%s`', $callable[1]);
|
||||
$string .= "\n".\sprintf('- Class: `%s`', $callable[0]);
|
||||
$string .= "\n- Static: yes";
|
||||
} else {
|
||||
$string .= "\n".\sprintf('- Name: `%s`', substr($callable[1], 8));
|
||||
$string .= "\n".\sprintf('- Class: `%s`', $callable[0]);
|
||||
$string .= "\n- Static: yes";
|
||||
$string .= "\n- Parent: yes";
|
||||
}
|
||||
}
|
||||
|
||||
$this->write($string."\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (\is_string($callable)) {
|
||||
$string .= "\n- Type: `function`";
|
||||
|
||||
if (!str_contains($callable, '::')) {
|
||||
$string .= "\n".\sprintf('- Name: `%s`', $callable);
|
||||
} else {
|
||||
$callableParts = explode('::', $callable);
|
||||
|
||||
$string .= "\n".\sprintf('- Name: `%s`', $callableParts[1]);
|
||||
$string .= "\n".\sprintf('- Class: `%s`', $callableParts[0]);
|
||||
$string .= "\n- Static: yes";
|
||||
}
|
||||
|
||||
$this->write($string."\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($callable instanceof \Closure) {
|
||||
$string .= "\n- Type: `closure`";
|
||||
|
||||
$r = new \ReflectionFunction($callable);
|
||||
if ($r->isAnonymous()) {
|
||||
$this->write($string."\n");
|
||||
|
||||
return;
|
||||
}
|
||||
$string .= "\n".\sprintf('- Name: `%s`', $r->name);
|
||||
|
||||
if ($class = $r->getClosureCalledClass()) {
|
||||
$string .= "\n".\sprintf('- Class: `%s`', $class->name);
|
||||
if (!$r->getClosureThis()) {
|
||||
$string .= "\n- Static: yes";
|
||||
}
|
||||
}
|
||||
|
||||
$this->write($string."\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (method_exists($callable, '__invoke')) {
|
||||
$string .= "\n- Type: `object`";
|
||||
$string .= "\n".\sprintf('- Name: `%s`', $callable::class);
|
||||
|
||||
$this->write($string."\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Callable is not describable.');
|
||||
}
|
||||
|
||||
private function formatRouterConfig(array $array): string
|
||||
{
|
||||
if (!$array) {
|
||||
return 'NONE';
|
||||
}
|
||||
|
||||
$string = '';
|
||||
ksort($array);
|
||||
foreach ($array as $name => $value) {
|
||||
$string .= "\n".' - `'.$name.'`: '.$this->formatValue($value);
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
673
vendor/symfony/framework-bundle/Console/Descriptor/TextDescriptor.php
vendored
Normal file
673
vendor/symfony/framework-bundle/Console/Descriptor/TextDescriptor.php
vendored
Normal file
@@ -0,0 +1,673 @@
|
||||
<?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\Bundle\FrameworkBundle\Console\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
use Symfony\Component\Console\Helper\Dumper;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Helper\TableCell;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class TextDescriptor extends Descriptor
|
||||
{
|
||||
public function __construct(
|
||||
private ?FileLinkFormatter $fileLinkFormatter = null,
|
||||
) {
|
||||
}
|
||||
|
||||
protected function describeRouteCollection(RouteCollection $routes, array $options = []): void
|
||||
{
|
||||
$showControllers = isset($options['show_controllers']) && $options['show_controllers'];
|
||||
|
||||
$tableHeaders = ['Name', 'Method', 'Scheme', 'Host', 'Path'];
|
||||
if ($showControllers) {
|
||||
$tableHeaders[] = 'Controller';
|
||||
}
|
||||
|
||||
if ($showAliases = $options['show_aliases'] ?? false) {
|
||||
$tableHeaders[] = 'Aliases';
|
||||
}
|
||||
|
||||
$tableRows = [];
|
||||
foreach ($routes->all() as $name => $route) {
|
||||
$controller = $route->getDefault('_controller');
|
||||
|
||||
$row = [
|
||||
$name,
|
||||
$route->getMethods() ? implode('|', $route->getMethods()) : 'ANY',
|
||||
$route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY',
|
||||
'' !== $route->getHost() ? $route->getHost() : 'ANY',
|
||||
$this->formatControllerLink($controller, $route->getPath(), $options['container'] ?? null),
|
||||
];
|
||||
|
||||
if ($showControllers) {
|
||||
$row[] = $controller ? $this->formatControllerLink($controller, $this->formatCallable($controller), $options['container'] ?? null) : '';
|
||||
}
|
||||
|
||||
if ($showAliases) {
|
||||
$row[] = implode('|', ($reverseAliases ??= $this->getReverseAliases($routes))[$name] ?? []);
|
||||
}
|
||||
|
||||
$tableRows[] = $row;
|
||||
}
|
||||
|
||||
if (isset($options['output'])) {
|
||||
$options['output']->table($tableHeaders, $tableRows);
|
||||
} else {
|
||||
$table = new Table($this->getOutput());
|
||||
$table->setHeaders($tableHeaders)->setRows($tableRows);
|
||||
$table->render();
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeRoute(Route $route, array $options = []): void
|
||||
{
|
||||
$defaults = $route->getDefaults();
|
||||
if (isset($defaults['_controller'])) {
|
||||
$defaults['_controller'] = $this->formatControllerLink($defaults['_controller'], $this->formatCallable($defaults['_controller']), $options['container'] ?? null);
|
||||
}
|
||||
|
||||
$tableHeaders = ['Property', 'Value'];
|
||||
$tableRows = [
|
||||
['Route Name', $options['name'] ?? ''],
|
||||
['Path', $route->getPath()],
|
||||
['Path Regex', $route->compile()->getRegex()],
|
||||
['Host', '' !== $route->getHost() ? $route->getHost() : 'ANY'],
|
||||
['Host Regex', '' !== $route->getHost() ? $route->compile()->getHostRegex() : ''],
|
||||
['Scheme', $route->getSchemes() ? implode('|', $route->getSchemes()) : 'ANY'],
|
||||
['Method', $route->getMethods() ? implode('|', $route->getMethods()) : 'ANY'],
|
||||
['Requirements', $route->getRequirements() ? $this->formatRouterConfig($route->getRequirements()) : 'NO CUSTOM'],
|
||||
['Class', $route::class],
|
||||
['Defaults', $this->formatRouterConfig($defaults)],
|
||||
['Options', $this->formatRouterConfig($route->getOptions())],
|
||||
];
|
||||
|
||||
if ('' !== $route->getCondition()) {
|
||||
$tableRows[] = ['Condition', $route->getCondition()];
|
||||
}
|
||||
|
||||
$table = new Table($this->getOutput());
|
||||
$table->setHeaders($tableHeaders)->setRows($tableRows);
|
||||
$table->render();
|
||||
}
|
||||
|
||||
protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void
|
||||
{
|
||||
$tableHeaders = ['Parameter', 'Value'];
|
||||
|
||||
$deprecatedParameters = $parameters->allDeprecated();
|
||||
|
||||
$tableRows = [];
|
||||
foreach ($this->sortParameters($parameters) as $parameter => $value) {
|
||||
$tableRows[] = [$parameter, $this->formatParameter($value)];
|
||||
|
||||
if (isset($deprecatedParameters[$parameter])) {
|
||||
$tableRows[] = [new TableCell(
|
||||
\sprintf('<comment>(Since %s %s: %s)</comment>', $deprecatedParameters[$parameter][0], $deprecatedParameters[$parameter][1], \sprintf(...\array_slice($deprecatedParameters[$parameter], 2))),
|
||||
['colspan' => 2]
|
||||
)];
|
||||
}
|
||||
}
|
||||
|
||||
$options['output']->title('Symfony Container Parameters');
|
||||
$options['output']->table($tableHeaders, $tableRows);
|
||||
}
|
||||
|
||||
protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
|
||||
|
||||
if ($showHidden) {
|
||||
$options['output']->title('Symfony Container Hidden Tags');
|
||||
} else {
|
||||
$options['output']->title('Symfony Container Tags');
|
||||
}
|
||||
|
||||
foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
|
||||
$options['output']->section(\sprintf('"%s" tag', $tag));
|
||||
$options['output']->listing(array_keys($definitions));
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeContainerService(object $service, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
if (!isset($options['id'])) {
|
||||
throw new \InvalidArgumentException('An "id" option must be provided.');
|
||||
}
|
||||
|
||||
if ($service instanceof Alias) {
|
||||
$this->describeContainerAlias($service, $options, $container);
|
||||
} elseif ($service instanceof Definition) {
|
||||
$this->describeContainerDefinition($service, $options, $container);
|
||||
} else {
|
||||
$options['output']->title(\sprintf('Information for Service "<info>%s</info>"', $options['id']));
|
||||
$options['output']->table(
|
||||
['Service ID', 'Class'],
|
||||
[
|
||||
[$options['id'], $service::class],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$showHidden = isset($options['show_hidden']) && $options['show_hidden'];
|
||||
$showTag = $options['tag'] ?? null;
|
||||
|
||||
if ($showHidden) {
|
||||
$title = 'Symfony Container Hidden Services';
|
||||
} else {
|
||||
$title = 'Symfony Container Services';
|
||||
}
|
||||
|
||||
if ($showTag) {
|
||||
$title .= \sprintf(' Tagged with "%s" Tag', $options['tag']);
|
||||
}
|
||||
|
||||
$options['output']->title($title);
|
||||
|
||||
$serviceIds = isset($options['tag']) && $options['tag']
|
||||
? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($options['tag']))
|
||||
: $this->sortServiceIds($container->getServiceIds());
|
||||
$maxTags = [];
|
||||
|
||||
if (isset($options['filter'])) {
|
||||
$serviceIds = array_filter($serviceIds, $options['filter']);
|
||||
}
|
||||
|
||||
foreach ($serviceIds as $key => $serviceId) {
|
||||
$definition = $this->resolveServiceDefinition($container, $serviceId);
|
||||
|
||||
// filter out hidden services unless shown explicitly
|
||||
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
|
||||
unset($serviceIds[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($definition instanceof Definition) {
|
||||
if ($definition->hasTag('container.excluded')) {
|
||||
unset($serviceIds[$key]);
|
||||
continue;
|
||||
}
|
||||
if ($showTag) {
|
||||
$tags = $definition->getTag($showTag);
|
||||
foreach ($tags as $tag) {
|
||||
foreach ($tag as $key => $value) {
|
||||
if (!isset($maxTags[$key])) {
|
||||
$maxTags[$key] = \strlen($key);
|
||||
}
|
||||
if (\is_array($value)) {
|
||||
$value = $this->formatParameter($value);
|
||||
}
|
||||
|
||||
if (\strlen($value) > $maxTags[$key]) {
|
||||
$maxTags[$key] = \strlen($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$tagsCount = \count($maxTags);
|
||||
$tagsNames = array_keys($maxTags);
|
||||
|
||||
$tableHeaders = array_merge(['Service ID'], $tagsNames, ['Class name']);
|
||||
$tableRows = [];
|
||||
$rawOutput = isset($options['raw_text']) && $options['raw_text'];
|
||||
foreach ($serviceIds as $serviceId) {
|
||||
$definition = $this->resolveServiceDefinition($container, $serviceId);
|
||||
|
||||
$styledServiceId = $rawOutput ? $serviceId : \sprintf('<fg=cyan>%s</fg=cyan>', OutputFormatter::escape($serviceId));
|
||||
if ($definition instanceof Definition) {
|
||||
if ($showTag) {
|
||||
foreach ($this->sortByPriority($definition->getTag($showTag)) as $key => $tag) {
|
||||
$tagValues = [];
|
||||
foreach ($tagsNames as $tagName) {
|
||||
if (\is_array($tagValue = $tag[$tagName] ?? '')) {
|
||||
$tagValue = $this->formatParameter($tagValue);
|
||||
}
|
||||
|
||||
$tagValues[] = $tagValue;
|
||||
}
|
||||
if (0 === $key) {
|
||||
$tableRows[] = array_merge([$serviceId], $tagValues, [$definition->getClass()]);
|
||||
} else {
|
||||
$tableRows[] = array_merge([' (same service as previous, another tag)'], $tagValues, ['']);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$tableRows[] = [$styledServiceId, $definition->getClass()];
|
||||
}
|
||||
} elseif ($definition instanceof Alias) {
|
||||
$alias = $definition;
|
||||
$tableRows[] = array_merge([$styledServiceId, \sprintf('alias for "%s"', $alias)], $tagsCount ? array_fill(0, $tagsCount, '') : []);
|
||||
} else {
|
||||
$tableRows[] = array_merge([$styledServiceId, $definition::class], $tagsCount ? array_fill(0, $tagsCount, '') : []);
|
||||
}
|
||||
}
|
||||
|
||||
$options['output']->table($tableHeaders, $tableRows);
|
||||
}
|
||||
|
||||
protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
if (isset($options['id'])) {
|
||||
$options['output']->title(\sprintf('Information for Service "<info>%s</info>"', $options['id']));
|
||||
}
|
||||
|
||||
if ('' !== $classDescription = $this->getClassDescription((string) $definition->getClass())) {
|
||||
$options['output']->text($classDescription."\n");
|
||||
}
|
||||
|
||||
$tableHeaders = ['Option', 'Value'];
|
||||
|
||||
$tableRows[] = ['Service ID', $options['id'] ?? '-'];
|
||||
$tableRows[] = ['Class', $definition->getClass() ?: '-'];
|
||||
|
||||
$omitTags = isset($options['omit_tags']) && $options['omit_tags'];
|
||||
if (!$omitTags && ($tags = $definition->getTags())) {
|
||||
$tagInformation = [];
|
||||
foreach ($tags as $tagName => $tagData) {
|
||||
foreach ($tagData as $tagParameters) {
|
||||
$parameters = array_map(fn ($key, $value) => \sprintf('<info>%s</info>: %s', $key, \is_array($value) ? $this->formatParameter($value) : $value), array_keys($tagParameters), array_values($tagParameters));
|
||||
$parameters = implode(', ', $parameters);
|
||||
|
||||
if ('' === $parameters) {
|
||||
$tagInformation[] = \sprintf('%s', $tagName);
|
||||
} else {
|
||||
$tagInformation[] = \sprintf('%s (%s)', $tagName, $parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
$tagInformation = implode("\n", $tagInformation);
|
||||
} else {
|
||||
$tagInformation = '-';
|
||||
}
|
||||
$tableRows[] = ['Tags', $tagInformation];
|
||||
|
||||
$calls = $definition->getMethodCalls();
|
||||
if (\count($calls) > 0) {
|
||||
$callInformation = [];
|
||||
foreach ($calls as $call) {
|
||||
$callInformation[] = $call[0];
|
||||
}
|
||||
$tableRows[] = ['Calls', implode(', ', $callInformation)];
|
||||
}
|
||||
|
||||
$tableRows[] = ['Public', $definition->isPublic() && !$definition->isPrivate() ? 'yes' : 'no'];
|
||||
$tableRows[] = ['Synthetic', $definition->isSynthetic() ? 'yes' : 'no'];
|
||||
$tableRows[] = ['Lazy', $definition->isLazy() ? 'yes' : 'no'];
|
||||
$tableRows[] = ['Shared', $definition->isShared() ? 'yes' : 'no'];
|
||||
$tableRows[] = ['Abstract', $definition->isAbstract() ? 'yes' : 'no'];
|
||||
$tableRows[] = ['Autowired', $definition->isAutowired() ? 'yes' : 'no'];
|
||||
$tableRows[] = ['Autoconfigured', $definition->isAutoconfigured() ? 'yes' : 'no'];
|
||||
|
||||
if ($definition->getFile()) {
|
||||
$tableRows[] = ['Required File', $definition->getFile()];
|
||||
}
|
||||
|
||||
if ($factory = $definition->getFactory()) {
|
||||
if (\is_array($factory)) {
|
||||
if ($factory[0] instanceof Reference) {
|
||||
$tableRows[] = ['Factory Service', $factory[0]];
|
||||
} elseif ($factory[0] instanceof Definition) {
|
||||
$tableRows[] = ['Factory Service', \sprintf('inline factory service (%s)', $factory[0]->getClass() ?? 'class not configured')];
|
||||
} else {
|
||||
$tableRows[] = ['Factory Class', $factory[0]];
|
||||
}
|
||||
$tableRows[] = ['Factory Method', $factory[1]];
|
||||
} else {
|
||||
$tableRows[] = ['Factory Function', $factory];
|
||||
}
|
||||
}
|
||||
|
||||
$argumentsInformation = [];
|
||||
if ($arguments = $definition->getArguments()) {
|
||||
foreach ($arguments as $argument) {
|
||||
if ($argument instanceof ServiceClosureArgument) {
|
||||
$argument = $argument->getValues()[0];
|
||||
}
|
||||
if ($argument instanceof Reference) {
|
||||
$argumentsInformation[] = \sprintf('Service(%s)', (string) $argument);
|
||||
} elseif ($argument instanceof IteratorArgument) {
|
||||
if ($argument instanceof TaggedIteratorArgument) {
|
||||
$argumentsInformation[] = \sprintf('Tagged Iterator for "%s"%s', $argument->getTag(), $options['is_debug'] ? '' : \sprintf(' (%d element(s))', \count($argument->getValues())));
|
||||
} else {
|
||||
$argumentsInformation[] = \sprintf('Iterator (%d element(s))', \count($argument->getValues()));
|
||||
}
|
||||
|
||||
foreach ($argument->getValues() as $ref) {
|
||||
$argumentsInformation[] = \sprintf('- Service(%s)', $ref);
|
||||
}
|
||||
} elseif ($argument instanceof ServiceLocatorArgument) {
|
||||
$argumentsInformation[] = \sprintf('Service locator (%d element(s))', \count($argument->getValues()));
|
||||
} elseif ($argument instanceof Definition) {
|
||||
$argumentsInformation[] = 'Inlined Service';
|
||||
} elseif ($argument instanceof \UnitEnum) {
|
||||
$argumentsInformation[] = ltrim(var_export($argument, true), '\\');
|
||||
} elseif ($argument instanceof AbstractArgument) {
|
||||
$argumentsInformation[] = \sprintf('Abstract argument (%s)', $argument->getText());
|
||||
} else {
|
||||
$argumentsInformation[] = \is_array($argument) ? \sprintf('Array (%d element(s))', \count($argument)) : $argument;
|
||||
}
|
||||
}
|
||||
|
||||
$tableRows[] = ['Arguments', implode("\n", $argumentsInformation)];
|
||||
}
|
||||
|
||||
$inEdges = null !== $container && isset($options['id']) ? $this->getServiceEdges($container, $options['id']) : [];
|
||||
$tableRows[] = ['Usages', $inEdges ? implode(\PHP_EOL, $inEdges) : 'none'];
|
||||
|
||||
$options['output']->table($tableHeaders, $tableRows);
|
||||
}
|
||||
|
||||
protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$containerDeprecationFilePath = \sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
|
||||
if (!file_exists($containerDeprecationFilePath)) {
|
||||
$options['output']->warning('The deprecation file does not exist, please try warming the cache first.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$logs = unserialize(file_get_contents($containerDeprecationFilePath));
|
||||
if (0 === \count($logs)) {
|
||||
$options['output']->success('There are no deprecations in the logs!');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$formattedLogs = [];
|
||||
$remainingCount = 0;
|
||||
foreach ($logs as $log) {
|
||||
$formattedLogs[] = \sprintf("%sx: %s\n in %s:%s", $log['count'], $log['message'], $log['file'], $log['line']);
|
||||
$remainingCount += $log['count'];
|
||||
}
|
||||
$options['output']->title(\sprintf('Remaining deprecations (%s)', $remainingCount));
|
||||
$options['output']->listing($formattedLogs);
|
||||
}
|
||||
|
||||
protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
if ($alias->isPublic() && !$alias->isPrivate()) {
|
||||
$options['output']->comment(\sprintf('This service is a <info>public</info> alias for the service <info>%s</info>', (string) $alias));
|
||||
} else {
|
||||
$options['output']->comment(\sprintf('This service is a <comment>private</comment> alias for the service <info>%s</info>', (string) $alias));
|
||||
}
|
||||
|
||||
if (!$container) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->describeContainerDefinition($container->getDefinition((string) $alias), array_merge($options, ['id' => (string) $alias]), $container);
|
||||
}
|
||||
|
||||
protected function describeContainerParameter(mixed $parameter, ?array $deprecation, array $options = []): void
|
||||
{
|
||||
$parameterName = $options['parameter'];
|
||||
$rows = [
|
||||
[$parameterName, $this->formatParameter($parameter)],
|
||||
];
|
||||
|
||||
if ($deprecation) {
|
||||
$rows[] = [new TableCell(
|
||||
\sprintf('<comment>(Since %s %s: %s)</comment>', $deprecation[0], $deprecation[1], \sprintf(...\array_slice($deprecation, 2))),
|
||||
['colspan' => 2]
|
||||
)];
|
||||
}
|
||||
|
||||
$options['output']->table(['Parameter', 'Value'], $rows);
|
||||
}
|
||||
|
||||
protected function describeContainerEnvVars(array $envs, array $options = []): void
|
||||
{
|
||||
$dump = new Dumper($this->output);
|
||||
$options['output']->title('Symfony Container Environment Variables');
|
||||
|
||||
if (null !== $name = $options['name'] ?? null) {
|
||||
$options['output']->comment('Displaying detailed environment variable usage matching '.$name);
|
||||
|
||||
$matches = false;
|
||||
foreach ($envs as $env) {
|
||||
if ($name === $env['name'] || false !== stripos($env['name'], $name)) {
|
||||
$matches = true;
|
||||
$options['output']->section('%env('.$env['processor'].':'.$env['name'].')%');
|
||||
$options['output']->table([], [
|
||||
['<info>Default value</>', $env['default_available'] ? $dump($env['default_value']) : 'n/a'],
|
||||
['<info>Real value</>', $env['runtime_available'] ? $dump($env['runtime_value']) : 'n/a'],
|
||||
['<info>Processed value</>', $env['default_available'] || $env['runtime_available'] ? $dump($env['processed_value']) : 'n/a'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$matches) {
|
||||
$options['output']->block('None of the environment variables match this name.');
|
||||
} else {
|
||||
$options['output']->comment('Note real values might be different between web and CLI.');
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$envs) {
|
||||
$options['output']->block('No environment variables are being used.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$rows = [];
|
||||
$missing = [];
|
||||
foreach ($envs as $env) {
|
||||
if (isset($rows[$env['name']])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rows[$env['name']] = [
|
||||
$env['name'],
|
||||
$env['default_available'] ? $dump($env['default_value']) : 'n/a',
|
||||
$env['runtime_available'] ? $dump($env['runtime_value']) : 'n/a',
|
||||
];
|
||||
if (!$env['default_available'] && !$env['runtime_available']) {
|
||||
$missing[$env['name']] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$options['output']->table(['Name', 'Default value', 'Real value'], $rows);
|
||||
$options['output']->comment('Note real values might be different between web and CLI.');
|
||||
|
||||
if ($missing) {
|
||||
$options['output']->warning('The following variables are missing:');
|
||||
$options['output']->listing(array_keys($missing));
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []): void
|
||||
{
|
||||
$event = $options['event'] ?? null;
|
||||
$dispatcherServiceName = $options['dispatcher_service_name'] ?? null;
|
||||
|
||||
$title = 'Registered Listeners';
|
||||
|
||||
if (null !== $dispatcherServiceName) {
|
||||
$title .= \sprintf(' of Event Dispatcher "%s"', $dispatcherServiceName);
|
||||
}
|
||||
|
||||
if (null !== $event) {
|
||||
$title .= \sprintf(' for "%s" Event', $event);
|
||||
$registeredListeners = $eventDispatcher->getListeners($event);
|
||||
} else {
|
||||
$title .= ' Grouped by Event';
|
||||
// Try to see if "events" exists
|
||||
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(fn ($event) => $eventDispatcher->getListeners($event), $options['events'])) : $eventDispatcher->getListeners();
|
||||
}
|
||||
|
||||
$options['output']->title($title);
|
||||
if (null !== $event) {
|
||||
$this->renderEventListenerTable($eventDispatcher, $event, $registeredListeners, $options['output']);
|
||||
} else {
|
||||
ksort($registeredListeners);
|
||||
foreach ($registeredListeners as $eventListened => $eventListeners) {
|
||||
$options['output']->section(\sprintf('"%s" event', $eventListened));
|
||||
$this->renderEventListenerTable($eventDispatcher, $eventListened, $eventListeners, $options['output']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function describeCallable(mixed $callable, array $options = []): void
|
||||
{
|
||||
$this->writeText($this->formatCallable($callable), $options);
|
||||
}
|
||||
|
||||
private function renderEventListenerTable(EventDispatcherInterface $eventDispatcher, string $event, array $eventListeners, SymfonyStyle $io): void
|
||||
{
|
||||
$tableHeaders = ['Order', 'Callable', 'Priority'];
|
||||
$tableRows = [];
|
||||
|
||||
foreach ($eventListeners as $order => $listener) {
|
||||
$tableRows[] = [\sprintf('#%d', $order + 1), $this->formatCallable($listener), $eventDispatcher->getListenerPriority($event, $listener)];
|
||||
}
|
||||
|
||||
$io->table($tableHeaders, $tableRows);
|
||||
}
|
||||
|
||||
private function formatRouterConfig(array $config): string
|
||||
{
|
||||
if (!$config) {
|
||||
return 'NONE';
|
||||
}
|
||||
|
||||
ksort($config);
|
||||
|
||||
$configAsString = '';
|
||||
foreach ($config as $key => $value) {
|
||||
$configAsString .= \sprintf("\n%s: %s", $key, $this->formatValue($value));
|
||||
}
|
||||
|
||||
return trim($configAsString);
|
||||
}
|
||||
|
||||
private function formatControllerLink(mixed $controller, string $anchorText, ?callable $getContainer = null): string
|
||||
{
|
||||
if (null === $this->fileLinkFormatter) {
|
||||
return $anchorText;
|
||||
}
|
||||
|
||||
try {
|
||||
if (null === $controller) {
|
||||
return $anchorText;
|
||||
} elseif (\is_array($controller)) {
|
||||
$r = new \ReflectionMethod($controller[0], $controller[1]);
|
||||
} elseif ($controller instanceof \Closure) {
|
||||
$r = new \ReflectionFunction($controller);
|
||||
} elseif (method_exists($controller, '__invoke')) {
|
||||
$r = new \ReflectionMethod($controller, '__invoke');
|
||||
} elseif (!\is_string($controller)) {
|
||||
return $anchorText;
|
||||
} elseif (str_contains($controller, '::')) {
|
||||
$r = new \ReflectionMethod(...explode('::', $controller, 2));
|
||||
} else {
|
||||
$r = new \ReflectionFunction($controller);
|
||||
}
|
||||
} catch (\ReflectionException) {
|
||||
if (\is_array($controller)) {
|
||||
$controller = implode('::', $controller);
|
||||
}
|
||||
|
||||
$id = $controller;
|
||||
$method = '__invoke';
|
||||
|
||||
if ($pos = strpos($controller, '::')) {
|
||||
$id = substr($controller, 0, $pos);
|
||||
$method = substr($controller, $pos + 2);
|
||||
}
|
||||
|
||||
if (!$getContainer || !($container = $getContainer()) || !$container->has($id)) {
|
||||
return $anchorText;
|
||||
}
|
||||
|
||||
try {
|
||||
$r = new \ReflectionMethod($container->findDefinition($id)->getClass(), $method);
|
||||
} catch (\ReflectionException) {
|
||||
return $anchorText;
|
||||
}
|
||||
}
|
||||
|
||||
$fileLink = $this->fileLinkFormatter->format($r->getFileName(), $r->getStartLine());
|
||||
if ($fileLink) {
|
||||
return \sprintf('<href=%s>%s</>', $fileLink, $anchorText);
|
||||
}
|
||||
|
||||
return $anchorText;
|
||||
}
|
||||
|
||||
private function formatCallable(mixed $callable): string
|
||||
{
|
||||
if (\is_array($callable)) {
|
||||
if (\is_object($callable[0])) {
|
||||
return \sprintf('%s::%s()', $callable[0]::class, $callable[1]);
|
||||
}
|
||||
|
||||
return \sprintf('%s::%s()', $callable[0], $callable[1]);
|
||||
}
|
||||
|
||||
if (\is_string($callable)) {
|
||||
return \sprintf('%s()', $callable);
|
||||
}
|
||||
|
||||
if ($callable instanceof \Closure) {
|
||||
$r = new \ReflectionFunction($callable);
|
||||
if ($r->isAnonymous()) {
|
||||
return 'Closure()';
|
||||
}
|
||||
if ($class = $r->getClosureCalledClass()) {
|
||||
return \sprintf('%s::%s()', $class->name, $r->name);
|
||||
}
|
||||
|
||||
return $r->name.'()';
|
||||
}
|
||||
|
||||
if (method_exists($callable, '__invoke')) {
|
||||
return \sprintf('%s::__invoke()', $callable::class);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Callable is not describable.');
|
||||
}
|
||||
|
||||
private function writeText(string $content, array $options = []): void
|
||||
{
|
||||
$this->write(
|
||||
isset($options['raw_text']) && $options['raw_text'] ? strip_tags($content) : $content,
|
||||
isset($options['raw_output']) ? !$options['raw_output'] : true
|
||||
);
|
||||
}
|
||||
}
|
||||
606
vendor/symfony/framework-bundle/Console/Descriptor/XmlDescriptor.php
vendored
Normal file
606
vendor/symfony/framework-bundle/Console/Descriptor/XmlDescriptor.php
vendored
Normal file
@@ -0,0 +1,606 @@
|
||||
<?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\Bundle\FrameworkBundle\Console\Descriptor;
|
||||
|
||||
use Symfony\Component\Console\Exception\LogicException;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Alias;
|
||||
use Symfony\Component\DependencyInjection\Argument\AbstractArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class XmlDescriptor extends Descriptor
|
||||
{
|
||||
protected function describeRouteCollection(RouteCollection $routes, array $options = []): void
|
||||
{
|
||||
$this->writeDocument($this->getRouteCollectionDocument($routes, $options));
|
||||
}
|
||||
|
||||
protected function describeRoute(Route $route, array $options = []): void
|
||||
{
|
||||
$this->writeDocument($this->getRouteDocument($route, $options['name'] ?? null));
|
||||
}
|
||||
|
||||
protected function describeContainerParameters(ParameterBag $parameters, array $options = []): void
|
||||
{
|
||||
$this->writeDocument($this->getContainerParametersDocument($parameters));
|
||||
}
|
||||
|
||||
protected function describeContainerTags(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$this->writeDocument($this->getContainerTagsDocument($container, isset($options['show_hidden']) && $options['show_hidden']));
|
||||
}
|
||||
|
||||
protected function describeContainerService(object $service, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
if (!isset($options['id'])) {
|
||||
throw new \InvalidArgumentException('An "id" option must be provided.');
|
||||
}
|
||||
|
||||
$this->writeDocument($this->getContainerServiceDocument($service, $options['id'], $container));
|
||||
}
|
||||
|
||||
protected function describeContainerServices(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$this->writeDocument($this->getContainerServicesDocument($container, $options['tag'] ?? null, isset($options['show_hidden']) && $options['show_hidden'], $options['filter'] ?? null));
|
||||
}
|
||||
|
||||
protected function describeContainerDefinition(Definition $definition, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
$this->writeDocument($this->getContainerDefinitionDocument($definition, $options['id'] ?? null, isset($options['omit_tags']) && $options['omit_tags'], $container));
|
||||
}
|
||||
|
||||
protected function describeContainerAlias(Alias $alias, array $options = [], ?ContainerBuilder $container = null): void
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($dom->importNode($this->getContainerAliasDocument($alias, $options['id'] ?? null)->childNodes->item(0), true));
|
||||
|
||||
if (!$container) {
|
||||
$this->writeDocument($dom);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($container->getDefinition((string) $alias), (string) $alias, false, $container)->childNodes->item(0), true));
|
||||
|
||||
$this->writeDocument($dom);
|
||||
}
|
||||
|
||||
protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []): void
|
||||
{
|
||||
$this->writeDocument($this->getEventDispatcherListenersDocument($eventDispatcher, $options));
|
||||
}
|
||||
|
||||
protected function describeCallable(mixed $callable, array $options = []): void
|
||||
{
|
||||
$this->writeDocument($this->getCallableDocument($callable));
|
||||
}
|
||||
|
||||
protected function describeContainerParameter(mixed $parameter, ?array $deprecation, array $options = []): void
|
||||
{
|
||||
$this->writeDocument($this->getContainerParameterDocument($parameter, $deprecation, $options));
|
||||
}
|
||||
|
||||
protected function describeContainerEnvVars(array $envs, array $options = []): void
|
||||
{
|
||||
throw new LogicException('Using the XML format to debug environment variables is not supported.');
|
||||
}
|
||||
|
||||
protected function describeContainerDeprecations(ContainerBuilder $container, array $options = []): void
|
||||
{
|
||||
$containerDeprecationFilePath = \sprintf('%s/%sDeprecations.log', $container->getParameter('kernel.build_dir'), $container->getParameter('kernel.container_class'));
|
||||
if (!file_exists($containerDeprecationFilePath)) {
|
||||
throw new RuntimeException('The deprecation file does not exist, please try warming the cache first.');
|
||||
}
|
||||
|
||||
$logs = unserialize(file_get_contents($containerDeprecationFilePath));
|
||||
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($deprecationsXML = $dom->createElement('deprecations'));
|
||||
|
||||
$remainingCount = 0;
|
||||
foreach ($logs as $log) {
|
||||
$deprecationsXML->appendChild($deprecationXML = $dom->createElement('deprecation'));
|
||||
$deprecationXML->setAttribute('count', $log['count']);
|
||||
$deprecationXML->appendChild($dom->createElement('message', $log['message']));
|
||||
$deprecationXML->appendChild($dom->createElement('file', $log['file']));
|
||||
$deprecationXML->appendChild($dom->createElement('line', $log['line']));
|
||||
$remainingCount += $log['count'];
|
||||
}
|
||||
|
||||
$deprecationsXML->setAttribute('remainingCount', $remainingCount);
|
||||
|
||||
$this->writeDocument($dom);
|
||||
}
|
||||
|
||||
private function writeDocument(\DOMDocument $dom): void
|
||||
{
|
||||
$dom->formatOutput = true;
|
||||
$this->write($dom->saveXML());
|
||||
}
|
||||
|
||||
private function getRouteCollectionDocument(RouteCollection $routes, array $options): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($routesXML = $dom->createElement('routes'));
|
||||
|
||||
foreach ($routes->all() as $name => $route) {
|
||||
$routeXML = $this->getRouteDocument($route, $name);
|
||||
if (($showAliases ??= $options['show_aliases'] ?? false) && $aliases = ($reverseAliases ??= $this->getReverseAliases($routes))[$name] ?? []) {
|
||||
$routeXML->firstChild->appendChild($aliasesXML = $routeXML->createElement('aliases'));
|
||||
foreach ($aliases as $alias) {
|
||||
$aliasesXML->appendChild($aliasXML = $routeXML->createElement('alias'));
|
||||
$aliasXML->appendChild(new \DOMText($alias));
|
||||
}
|
||||
}
|
||||
|
||||
$routesXML->appendChild($routesXML->ownerDocument->importNode($routeXML->childNodes->item(0), true));
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
private function getRouteDocument(Route $route, ?string $name = null): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($routeXML = $dom->createElement('route'));
|
||||
|
||||
if ($name) {
|
||||
$routeXML->setAttribute('name', $name);
|
||||
}
|
||||
|
||||
$routeXML->setAttribute('class', $route::class);
|
||||
|
||||
$routeXML->appendChild($pathXML = $dom->createElement('path'));
|
||||
$pathXML->setAttribute('regex', $route->compile()->getRegex());
|
||||
$pathXML->appendChild(new \DOMText($route->getPath()));
|
||||
|
||||
if ('' !== $route->getHost()) {
|
||||
$routeXML->appendChild($hostXML = $dom->createElement('host'));
|
||||
$hostXML->setAttribute('regex', $route->compile()->getHostRegex());
|
||||
$hostXML->appendChild(new \DOMText($route->getHost()));
|
||||
}
|
||||
|
||||
foreach ($route->getSchemes() as $scheme) {
|
||||
$routeXML->appendChild($schemeXML = $dom->createElement('scheme'));
|
||||
$schemeXML->appendChild(new \DOMText($scheme));
|
||||
}
|
||||
|
||||
foreach ($route->getMethods() as $method) {
|
||||
$routeXML->appendChild($methodXML = $dom->createElement('method'));
|
||||
$methodXML->appendChild(new \DOMText($method));
|
||||
}
|
||||
|
||||
if ($route->getDefaults()) {
|
||||
$routeXML->appendChild($defaultsXML = $dom->createElement('defaults'));
|
||||
foreach ($route->getDefaults() as $attribute => $value) {
|
||||
$defaultsXML->appendChild($defaultXML = $dom->createElement('default'));
|
||||
$defaultXML->setAttribute('key', $attribute);
|
||||
$defaultXML->appendChild(new \DOMText($this->formatValue($value)));
|
||||
}
|
||||
}
|
||||
|
||||
$originRequirements = $requirements = $route->getRequirements();
|
||||
unset($requirements['_scheme'], $requirements['_method']);
|
||||
if ($requirements) {
|
||||
$routeXML->appendChild($requirementsXML = $dom->createElement('requirements'));
|
||||
foreach ($originRequirements as $attribute => $pattern) {
|
||||
$requirementsXML->appendChild($requirementXML = $dom->createElement('requirement'));
|
||||
$requirementXML->setAttribute('key', $attribute);
|
||||
$requirementXML->appendChild(new \DOMText($pattern));
|
||||
}
|
||||
}
|
||||
|
||||
if ($route->getOptions()) {
|
||||
$routeXML->appendChild($optionsXML = $dom->createElement('options'));
|
||||
foreach ($route->getOptions() as $name => $value) {
|
||||
$optionsXML->appendChild($optionXML = $dom->createElement('option'));
|
||||
$optionXML->setAttribute('key', $name);
|
||||
$optionXML->appendChild(new \DOMText($this->formatValue($value)));
|
||||
}
|
||||
}
|
||||
|
||||
if ('' !== $route->getCondition()) {
|
||||
$routeXML->appendChild($conditionXML = $dom->createElement('condition'));
|
||||
$conditionXML->appendChild(new \DOMText($route->getCondition()));
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
private function getContainerParametersDocument(ParameterBag $parameters): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($parametersXML = $dom->createElement('parameters'));
|
||||
|
||||
$deprecatedParameters = $parameters->allDeprecated();
|
||||
|
||||
foreach ($this->sortParameters($parameters) as $key => $value) {
|
||||
$parametersXML->appendChild($parameterXML = $dom->createElement('parameter'));
|
||||
$parameterXML->setAttribute('key', $key);
|
||||
$parameterXML->appendChild(new \DOMText($this->formatParameter($value)));
|
||||
|
||||
if (isset($deprecatedParameters[$key])) {
|
||||
$parameterXML->setAttribute('deprecated', \sprintf('Since %s %s: %s', $deprecatedParameters[$key][0], $deprecatedParameters[$key][1], \sprintf(...\array_slice($deprecatedParameters[$key], 2))));
|
||||
}
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
private function getContainerTagsDocument(ContainerBuilder $container, bool $showHidden = false): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($containerXML = $dom->createElement('container'));
|
||||
|
||||
foreach ($this->findDefinitionsByTag($container, $showHidden) as $tag => $definitions) {
|
||||
$containerXML->appendChild($tagXML = $dom->createElement('tag'));
|
||||
$tagXML->setAttribute('name', $tag);
|
||||
|
||||
foreach ($definitions as $serviceId => $definition) {
|
||||
$definitionXML = $this->getContainerDefinitionDocument($definition, $serviceId, true, $container);
|
||||
$tagXML->appendChild($dom->importNode($definitionXML->childNodes->item(0), true));
|
||||
}
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
private function getContainerServiceDocument(object $service, string $id, ?ContainerBuilder $container = null): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
|
||||
if ($service instanceof Alias) {
|
||||
$dom->appendChild($dom->importNode($this->getContainerAliasDocument($service, $id)->childNodes->item(0), true));
|
||||
if ($container) {
|
||||
$dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($container->getDefinition((string) $service), (string) $service, false, $container)->childNodes->item(0), true));
|
||||
}
|
||||
} elseif ($service instanceof Definition) {
|
||||
$dom->appendChild($dom->importNode($this->getContainerDefinitionDocument($service, $id, false, $container)->childNodes->item(0), true));
|
||||
} else {
|
||||
$dom->appendChild($serviceXML = $dom->createElement('service'));
|
||||
$serviceXML->setAttribute('id', $id);
|
||||
$serviceXML->setAttribute('class', $service::class);
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
private function getContainerServicesDocument(ContainerBuilder $container, ?string $tag = null, bool $showHidden = false, ?callable $filter = null): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($containerXML = $dom->createElement('container'));
|
||||
|
||||
$serviceIds = $tag
|
||||
? $this->sortTaggedServicesByPriority($container->findTaggedServiceIds($tag))
|
||||
: $this->sortServiceIds($container->getServiceIds());
|
||||
if ($filter) {
|
||||
$serviceIds = array_filter($serviceIds, $filter);
|
||||
}
|
||||
|
||||
foreach ($serviceIds as $serviceId) {
|
||||
$service = $this->resolveServiceDefinition($container, $serviceId);
|
||||
|
||||
if ($showHidden xor '.' === ($serviceId[0] ?? null)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($service instanceof Definition && $service->hasTag('container.excluded')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$serviceXML = $this->getContainerServiceDocument($service, $serviceId, null);
|
||||
$containerXML->appendChild($containerXML->ownerDocument->importNode($serviceXML->childNodes->item(0), true));
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
private function getContainerDefinitionDocument(Definition $definition, ?string $id = null, bool $omitTags = false, ?ContainerBuilder $container = null): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($serviceXML = $dom->createElement('definition'));
|
||||
|
||||
if ($id) {
|
||||
$serviceXML->setAttribute('id', $id);
|
||||
}
|
||||
|
||||
if ('' !== $classDescription = $this->getClassDescription((string) $definition->getClass())) {
|
||||
$serviceXML->appendChild($descriptionXML = $dom->createElement('description'));
|
||||
$descriptionXML->appendChild($dom->createCDATASection($classDescription));
|
||||
}
|
||||
|
||||
$serviceXML->setAttribute('class', $definition->getClass() ?? '');
|
||||
|
||||
if ($factory = $definition->getFactory()) {
|
||||
$serviceXML->appendChild($factoryXML = $dom->createElement('factory'));
|
||||
|
||||
if (\is_array($factory)) {
|
||||
if ($factory[0] instanceof Reference) {
|
||||
$factoryXML->setAttribute('service', (string) $factory[0]);
|
||||
} elseif ($factory[0] instanceof Definition) {
|
||||
$factoryXML->setAttribute('service', \sprintf('inline factory service (%s)', $factory[0]->getClass() ?? 'not configured'));
|
||||
} else {
|
||||
$factoryXML->setAttribute('class', $factory[0]);
|
||||
}
|
||||
$factoryXML->setAttribute('method', $factory[1]);
|
||||
} else {
|
||||
$factoryXML->setAttribute('function', $factory);
|
||||
}
|
||||
}
|
||||
|
||||
$serviceXML->setAttribute('public', $definition->isPublic() && !$definition->isPrivate() ? 'true' : 'false');
|
||||
$serviceXML->setAttribute('synthetic', $definition->isSynthetic() ? 'true' : 'false');
|
||||
$serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false');
|
||||
$serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false');
|
||||
$serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false');
|
||||
$serviceXML->setAttribute('autowired', $definition->isAutowired() ? 'true' : 'false');
|
||||
$serviceXML->setAttribute('autoconfigured', $definition->isAutoconfigured() ? 'true' : 'false');
|
||||
if ($definition->isDeprecated()) {
|
||||
$serviceXML->setAttribute('deprecated', 'true');
|
||||
$serviceXML->setAttribute('deprecation_message', $definition->getDeprecation($id)['message']);
|
||||
} else {
|
||||
$serviceXML->setAttribute('deprecated', 'false');
|
||||
}
|
||||
$serviceXML->setAttribute('file', $definition->getFile() ?? '');
|
||||
|
||||
$calls = $definition->getMethodCalls();
|
||||
if (\count($calls) > 0) {
|
||||
$serviceXML->appendChild($callsXML = $dom->createElement('calls'));
|
||||
foreach ($calls as $callData) {
|
||||
$callsXML->appendChild($callXML = $dom->createElement('call'));
|
||||
$callXML->setAttribute('method', $callData[0]);
|
||||
if ($callData[2] ?? false) {
|
||||
$callXML->setAttribute('returns-clone', 'true');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->getArgumentNodes($definition->getArguments(), $dom, $container) as $node) {
|
||||
$serviceXML->appendChild($node);
|
||||
}
|
||||
|
||||
if (!$omitTags) {
|
||||
if ($tags = $this->sortTagsByPriority($definition->getTags())) {
|
||||
$serviceXML->appendChild($tagsXML = $dom->createElement('tags'));
|
||||
foreach ($tags as $tagName => $tagData) {
|
||||
foreach ($tagData as $parameters) {
|
||||
$tagsXML->appendChild($tagXML = $dom->createElement('tag'));
|
||||
$tagXML->setAttribute('name', $tagName);
|
||||
foreach ($parameters as $name => $value) {
|
||||
$tagXML->appendChild($parameterXML = $dom->createElement('parameter'));
|
||||
$parameterXML->setAttribute('name', $name);
|
||||
$parameterXML->appendChild(new \DOMText($this->formatParameter($value)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $container && null !== $id) {
|
||||
$edges = $this->getServiceEdges($container, $id);
|
||||
if ($edges) {
|
||||
$serviceXML->appendChild($usagesXML = $dom->createElement('usages'));
|
||||
foreach ($edges as $edge) {
|
||||
$usagesXML->appendChild($usageXML = $dom->createElement('usage'));
|
||||
$usageXML->appendChild(new \DOMText($edge));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DOMNode[]
|
||||
*/
|
||||
private function getArgumentNodes(array $arguments, \DOMDocument $dom, ?ContainerBuilder $container = null): array
|
||||
{
|
||||
$nodes = [];
|
||||
|
||||
foreach ($arguments as $argumentKey => $argument) {
|
||||
$argumentXML = $dom->createElement('argument');
|
||||
|
||||
if (\is_string($argumentKey)) {
|
||||
$argumentXML->setAttribute('key', $argumentKey);
|
||||
}
|
||||
|
||||
if ($argument instanceof ServiceClosureArgument) {
|
||||
$argument = $argument->getValues()[0];
|
||||
}
|
||||
|
||||
if ($argument instanceof Reference) {
|
||||
$argumentXML->setAttribute('type', 'service');
|
||||
$argumentXML->setAttribute('id', (string) $argument);
|
||||
} elseif ($argument instanceof IteratorArgument || $argument instanceof ServiceLocatorArgument) {
|
||||
$argumentXML->setAttribute('type', $argument instanceof IteratorArgument ? 'iterator' : 'service_locator');
|
||||
|
||||
foreach ($this->getArgumentNodes($argument->getValues(), $dom, $container) as $childArgumentXML) {
|
||||
$argumentXML->appendChild($childArgumentXML);
|
||||
}
|
||||
} elseif ($argument instanceof Definition) {
|
||||
$argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, $container)->childNodes->item(0), true));
|
||||
} elseif ($argument instanceof AbstractArgument) {
|
||||
$argumentXML->setAttribute('type', 'abstract');
|
||||
$argumentXML->appendChild(new \DOMText($argument->getText()));
|
||||
} elseif (\is_array($argument)) {
|
||||
$argumentXML->setAttribute('type', 'collection');
|
||||
|
||||
foreach ($this->getArgumentNodes($argument, $dom, $container) as $childArgumentXML) {
|
||||
$argumentXML->appendChild($childArgumentXML);
|
||||
}
|
||||
} elseif ($argument instanceof \UnitEnum) {
|
||||
$argumentXML->setAttribute('type', 'constant');
|
||||
$argumentXML->appendChild(new \DOMText(ltrim(var_export($argument, true), '\\')));
|
||||
} else {
|
||||
$argumentXML->appendChild(new \DOMText($argument));
|
||||
}
|
||||
|
||||
$nodes[] = $argumentXML;
|
||||
}
|
||||
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
private function getContainerAliasDocument(Alias $alias, ?string $id = null): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($aliasXML = $dom->createElement('alias'));
|
||||
|
||||
if ($id) {
|
||||
$aliasXML->setAttribute('id', $id);
|
||||
}
|
||||
|
||||
$aliasXML->setAttribute('service', (string) $alias);
|
||||
$aliasXML->setAttribute('public', $alias->isPublic() && !$alias->isPrivate() ? 'true' : 'false');
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
private function getContainerParameterDocument(mixed $parameter, ?array $deprecation, array $options = []): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($parameterXML = $dom->createElement('parameter'));
|
||||
|
||||
if (isset($options['parameter'])) {
|
||||
$parameterXML->setAttribute('key', $options['parameter']);
|
||||
|
||||
if ($deprecation) {
|
||||
$parameterXML->setAttribute('deprecated', \sprintf('Since %s %s: %s', $deprecation[0], $deprecation[1], \sprintf(...\array_slice($deprecation, 2))));
|
||||
}
|
||||
}
|
||||
|
||||
$parameterXML->appendChild(new \DOMText($this->formatParameter($parameter)));
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
private function getEventDispatcherListenersDocument(EventDispatcherInterface $eventDispatcher, array $options): \DOMDocument
|
||||
{
|
||||
$event = $options['event'] ?? null;
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($eventDispatcherXML = $dom->createElement('event-dispatcher'));
|
||||
|
||||
if (null !== $event) {
|
||||
$registeredListeners = $eventDispatcher->getListeners($event);
|
||||
$this->appendEventListenerDocument($eventDispatcher, $event, $eventDispatcherXML, $registeredListeners);
|
||||
} else {
|
||||
// Try to see if "events" exists
|
||||
$registeredListeners = \array_key_exists('events', $options) ? array_combine($options['events'], array_map(fn ($event) => $eventDispatcher->getListeners($event), $options['events'])) : $eventDispatcher->getListeners();
|
||||
ksort($registeredListeners);
|
||||
|
||||
foreach ($registeredListeners as $eventListened => $eventListeners) {
|
||||
$eventDispatcherXML->appendChild($eventXML = $dom->createElement('event'));
|
||||
$eventXML->setAttribute('name', $eventListened);
|
||||
|
||||
$this->appendEventListenerDocument($eventDispatcher, $eventListened, $eventXML, $eventListeners);
|
||||
}
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
private function appendEventListenerDocument(EventDispatcherInterface $eventDispatcher, string $event, \DOMElement $element, array $eventListeners): void
|
||||
{
|
||||
foreach ($eventListeners as $listener) {
|
||||
$callableXML = $this->getCallableDocument($listener);
|
||||
$callableXML->childNodes->item(0)->setAttribute('priority', $eventDispatcher->getListenerPriority($event, $listener));
|
||||
|
||||
$element->appendChild($element->ownerDocument->importNode($callableXML->childNodes->item(0), true));
|
||||
}
|
||||
}
|
||||
|
||||
private function getCallableDocument(mixed $callable): \DOMDocument
|
||||
{
|
||||
$dom = new \DOMDocument('1.0', 'UTF-8');
|
||||
$dom->appendChild($callableXML = $dom->createElement('callable'));
|
||||
|
||||
if (\is_array($callable)) {
|
||||
$callableXML->setAttribute('type', 'function');
|
||||
|
||||
if (\is_object($callable[0])) {
|
||||
$callableXML->setAttribute('name', $callable[1]);
|
||||
$callableXML->setAttribute('class', $callable[0]::class);
|
||||
} else {
|
||||
if (!str_starts_with($callable[1], 'parent::')) {
|
||||
$callableXML->setAttribute('name', $callable[1]);
|
||||
$callableXML->setAttribute('class', $callable[0]);
|
||||
$callableXML->setAttribute('static', 'true');
|
||||
} else {
|
||||
$callableXML->setAttribute('name', substr($callable[1], 8));
|
||||
$callableXML->setAttribute('class', $callable[0]);
|
||||
$callableXML->setAttribute('static', 'true');
|
||||
$callableXML->setAttribute('parent', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
if (\is_string($callable)) {
|
||||
$callableXML->setAttribute('type', 'function');
|
||||
|
||||
if (!str_contains($callable, '::')) {
|
||||
$callableXML->setAttribute('name', $callable);
|
||||
} else {
|
||||
$callableParts = explode('::', $callable);
|
||||
|
||||
$callableXML->setAttribute('name', $callableParts[1]);
|
||||
$callableXML->setAttribute('class', $callableParts[0]);
|
||||
$callableXML->setAttribute('static', 'true');
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
if ($callable instanceof \Closure) {
|
||||
$callableXML->setAttribute('type', 'closure');
|
||||
|
||||
$r = new \ReflectionFunction($callable);
|
||||
if ($r->isAnonymous()) {
|
||||
return $dom;
|
||||
}
|
||||
$callableXML->setAttribute('name', $r->name);
|
||||
|
||||
if ($class = $r->getClosureCalledClass()) {
|
||||
$callableXML->setAttribute('class', $class->name);
|
||||
if (!$r->getClosureThis()) {
|
||||
$callableXML->setAttribute('static', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
if (method_exists($callable, '__invoke')) {
|
||||
$callableXML->setAttribute('type', 'object');
|
||||
$callableXML->setAttribute('name', $callable::class);
|
||||
|
||||
return $dom;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Callable is not describable.');
|
||||
}
|
||||
}
|
||||
37
vendor/symfony/framework-bundle/Console/Helper/DescriptorHelper.php
vendored
Normal file
37
vendor/symfony/framework-bundle/Console/Helper/DescriptorHelper.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?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\Bundle\FrameworkBundle\Console\Helper;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\JsonDescriptor;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\MarkdownDescriptor;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\TextDescriptor;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Descriptor\XmlDescriptor;
|
||||
use Symfony\Component\Console\Helper\DescriptorHelper as BaseDescriptorHelper;
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
|
||||
|
||||
/**
|
||||
* @author Jean-François Simon <jeanfrancois.simon@sensiolabs.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class DescriptorHelper extends BaseDescriptorHelper
|
||||
{
|
||||
public function __construct(?FileLinkFormatter $fileLinkFormatter = null)
|
||||
{
|
||||
$this
|
||||
->register('txt', new TextDescriptor($fileLinkFormatter))
|
||||
->register('xml', new XmlDescriptor())
|
||||
->register('json', new JsonDescriptor())
|
||||
->register('md', new MarkdownDescriptor())
|
||||
;
|
||||
}
|
||||
}
|
||||
480
vendor/symfony/framework-bundle/Controller/AbstractController.php
vendored
Normal file
480
vendor/symfony/framework-bundle/Controller/AbstractController.php
vendored
Normal file
@@ -0,0 +1,480 @@
|
||||
<?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\Bundle\FrameworkBundle\Controller;
|
||||
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Link\EvolvableLinkInterface;
|
||||
use Psr\Link\LinkInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\DependencyInjection\ParameterBag\ContainerBagInterface;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||
use Symfony\Component\HttpFoundation\Session\FlashBagAwareSessionInterface;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AccessDecision;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
use Symfony\Component\Security\Csrf\CsrfToken;
|
||||
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
|
||||
use Symfony\Component\Serializer\SerializerInterface;
|
||||
use Symfony\Component\WebLink\EventListener\AddLinkHeaderListener;
|
||||
use Symfony\Component\WebLink\GenericLinkProvider;
|
||||
use Symfony\Component\WebLink\HttpHeaderSerializer;
|
||||
use Symfony\Contracts\Service\Attribute\Required;
|
||||
use Symfony\Contracts\Service\ServiceSubscriberInterface;
|
||||
use Twig\Environment;
|
||||
|
||||
/**
|
||||
* Provides shortcuts for HTTP-related features in controllers.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
abstract class AbstractController implements ServiceSubscriberInterface
|
||||
{
|
||||
protected ContainerInterface $container;
|
||||
|
||||
#[Required]
|
||||
public function setContainer(ContainerInterface $container): ?ContainerInterface
|
||||
{
|
||||
$previous = $this->container ?? null;
|
||||
$this->container = $container;
|
||||
|
||||
return $previous;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a container parameter by its name.
|
||||
*/
|
||||
protected function getParameter(string $name): array|bool|string|int|float|\UnitEnum|null
|
||||
{
|
||||
if (!$this->container->has('parameter_bag')) {
|
||||
throw new ServiceNotFoundException('parameter_bag.', null, null, [], \sprintf('The "%s::getParameter()" method is missing a parameter bag to work properly. Did you forget to register your controller as a service subscriber? This can be fixed either by using autoconfiguration or by manually wiring a "parameter_bag" in the service locator passed to the controller.', static::class));
|
||||
}
|
||||
|
||||
return $this->container->get('parameter_bag')->get($name);
|
||||
}
|
||||
|
||||
public static function getSubscribedServices(): array
|
||||
{
|
||||
return [
|
||||
'router' => '?'.RouterInterface::class,
|
||||
'request_stack' => '?'.RequestStack::class,
|
||||
'http_kernel' => '?'.HttpKernelInterface::class,
|
||||
'serializer' => '?'.SerializerInterface::class,
|
||||
'security.authorization_checker' => '?'.AuthorizationCheckerInterface::class,
|
||||
'twig' => '?'.Environment::class,
|
||||
'form.factory' => '?'.FormFactoryInterface::class,
|
||||
'security.token_storage' => '?'.TokenStorageInterface::class,
|
||||
'security.csrf.token_manager' => '?'.CsrfTokenManagerInterface::class,
|
||||
'parameter_bag' => '?'.ContainerBagInterface::class,
|
||||
'web_link.http_header_serializer' => '?'.HttpHeaderSerializer::class,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a URL from the given parameters.
|
||||
*
|
||||
* @see UrlGeneratorInterface
|
||||
*/
|
||||
protected function generateUrl(string $route, array $parameters = [], int $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH): string
|
||||
{
|
||||
return $this->container->get('router')->generate($route, $parameters, $referenceType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forwards the request to another controller.
|
||||
*
|
||||
* @param string $controller The controller name (a string like "App\Controller\PostController::index" or "App\Controller\PostController" if it is invokable)
|
||||
*/
|
||||
protected function forward(string $controller, array $path = [], array $query = []): Response
|
||||
{
|
||||
$request = $this->container->get('request_stack')->getCurrentRequest();
|
||||
$path['_controller'] = $controller;
|
||||
$subRequest = $request->duplicate($query, null, $path);
|
||||
|
||||
return $this->container->get('http_kernel')->handle($subRequest, HttpKernelInterface::SUB_REQUEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a RedirectResponse to the given URL.
|
||||
*
|
||||
* @param int $status The HTTP status code (302 "Found" by default)
|
||||
*/
|
||||
protected function redirect(string $url, int $status = 302): RedirectResponse
|
||||
{
|
||||
return new RedirectResponse($url, $status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a RedirectResponse to the given route with the given parameters.
|
||||
*
|
||||
* @param int $status The HTTP status code (302 "Found" by default)
|
||||
*/
|
||||
protected function redirectToRoute(string $route, array $parameters = [], int $status = 302): RedirectResponse
|
||||
{
|
||||
return $this->redirect($this->generateUrl($route, $parameters), $status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JsonResponse that uses the serializer component if enabled, or json_encode.
|
||||
*
|
||||
* @param int $status The HTTP status code (200 "OK" by default)
|
||||
*/
|
||||
protected function json(mixed $data, int $status = 200, array $headers = [], array $context = []): JsonResponse
|
||||
{
|
||||
if ($this->container->has('serializer')) {
|
||||
$json = $this->container->get('serializer')->serialize($data, 'json', array_merge([
|
||||
'json_encode_options' => JsonResponse::DEFAULT_ENCODING_OPTIONS,
|
||||
], $context));
|
||||
|
||||
return new JsonResponse($json, $status, $headers, true);
|
||||
}
|
||||
|
||||
return new JsonResponse($data, $status, $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a BinaryFileResponse object with original or customized file name and disposition header.
|
||||
*/
|
||||
protected function file(\SplFileInfo|string $file, ?string $fileName = null, string $disposition = ResponseHeaderBag::DISPOSITION_ATTACHMENT): BinaryFileResponse
|
||||
{
|
||||
$response = new BinaryFileResponse($file);
|
||||
$response->setContentDisposition($disposition, $fileName ?? $response->getFile()->getFilename());
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a flash message to the current session for type.
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function addFlash(string $type, mixed $message): void
|
||||
{
|
||||
try {
|
||||
$session = $this->container->get('request_stack')->getSession();
|
||||
} catch (SessionNotFoundException $e) {
|
||||
throw new \LogicException('You cannot use the addFlash method if sessions are disabled. Enable them in "config/packages/framework.yaml".', 0, $e);
|
||||
}
|
||||
|
||||
if (!$session instanceof FlashBagAwareSessionInterface) {
|
||||
throw new \LogicException(\sprintf('You cannot use the addFlash method because class "%s" doesn\'t implement "%s".', get_debug_type($session), FlashBagAwareSessionInterface::class));
|
||||
}
|
||||
|
||||
$session->getFlashBag()->add($type, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the attribute is granted against the current authentication token and optionally supplied subject.
|
||||
*
|
||||
* @throws \LogicException
|
||||
*/
|
||||
protected function isGranted(mixed $attribute, mixed $subject = null): bool
|
||||
{
|
||||
if (!$this->container->has('security.authorization_checker')) {
|
||||
throw new \LogicException('The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".');
|
||||
}
|
||||
|
||||
return $this->container->get('security.authorization_checker')->isGranted($attribute, $subject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the attribute is granted against the current authentication token and optionally supplied subject.
|
||||
*/
|
||||
protected function getAccessDecision(mixed $attribute, mixed $subject = null): AccessDecision
|
||||
{
|
||||
if (!$this->container->has('security.authorization_checker')) {
|
||||
throw new \LogicException('The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".');
|
||||
}
|
||||
|
||||
$accessDecision = new AccessDecision();
|
||||
$accessDecision->isGranted = $this->container->get('security.authorization_checker')->isGranted($attribute, $subject, $accessDecision);
|
||||
|
||||
return $accessDecision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an exception unless the attribute is granted against the current authentication token and optionally
|
||||
* supplied subject.
|
||||
*
|
||||
* @throws AccessDeniedException
|
||||
*/
|
||||
protected function denyAccessUnlessGranted(mixed $attribute, mixed $subject = null, string $message = 'Access Denied.'): void
|
||||
{
|
||||
if (class_exists(AccessDecision::class)) {
|
||||
$accessDecision = $this->getAccessDecision($attribute, $subject);
|
||||
$isGranted = $accessDecision->isGranted;
|
||||
} else {
|
||||
$accessDecision = null;
|
||||
$isGranted = $this->isGranted($attribute, $subject);
|
||||
}
|
||||
|
||||
if (!$isGranted) {
|
||||
$e = $this->createAccessDeniedException(3 > \func_num_args() && $accessDecision ? $accessDecision->getMessage() : $message);
|
||||
$e->setAttributes([$attribute]);
|
||||
$e->setSubject($subject);
|
||||
|
||||
if ($accessDecision) {
|
||||
$e->setAccessDecision($accessDecision);
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a rendered view.
|
||||
*
|
||||
* Forms found in parameters are auto-cast to form views.
|
||||
*/
|
||||
protected function renderView(string $view, array $parameters = []): string
|
||||
{
|
||||
return $this->doRenderView($view, null, $parameters, __FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a rendered block from a view.
|
||||
*
|
||||
* Forms found in parameters are auto-cast to form views.
|
||||
*/
|
||||
protected function renderBlockView(string $view, string $block, array $parameters = []): string
|
||||
{
|
||||
return $this->doRenderView($view, $block, $parameters, __FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a view.
|
||||
*
|
||||
* If an invalid form is found in the list of parameters, a 422 status code is returned.
|
||||
* Forms found in parameters are auto-cast to form views.
|
||||
*/
|
||||
protected function render(string $view, array $parameters = [], ?Response $response = null): Response
|
||||
{
|
||||
return $this->doRender($view, null, $parameters, $response, __FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a block in a view.
|
||||
*
|
||||
* If an invalid form is found in the list of parameters, a 422 status code is returned.
|
||||
* Forms found in parameters are auto-cast to form views.
|
||||
*/
|
||||
protected function renderBlock(string $view, string $block, array $parameters = [], ?Response $response = null): Response
|
||||
{
|
||||
return $this->doRender($view, $block, $parameters, $response, __FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Streams a view.
|
||||
*/
|
||||
protected function stream(string $view, array $parameters = [], ?StreamedResponse $response = null): StreamedResponse
|
||||
{
|
||||
if (!$this->container->has('twig')) {
|
||||
throw new \LogicException('You cannot use the "stream" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
|
||||
}
|
||||
|
||||
$twig = $this->container->get('twig');
|
||||
|
||||
$callback = function () use ($twig, $view, $parameters) {
|
||||
$twig->display($view, $parameters);
|
||||
};
|
||||
|
||||
if (null === $response) {
|
||||
return new StreamedResponse($callback);
|
||||
}
|
||||
|
||||
$response->setCallback($callback);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a NotFoundHttpException.
|
||||
*
|
||||
* This will result in a 404 response code. Usage example:
|
||||
*
|
||||
* throw $this->createNotFoundException('Page not found!');
|
||||
*/
|
||||
protected function createNotFoundException(string $message = 'Not Found', ?\Throwable $previous = null): NotFoundHttpException
|
||||
{
|
||||
return new NotFoundHttpException($message, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an AccessDeniedException.
|
||||
*
|
||||
* This will result in a 403 response code. Usage example:
|
||||
*
|
||||
* throw $this->createAccessDeniedException('Unable to access this page!');
|
||||
*
|
||||
* @throws \LogicException If the Security component is not available
|
||||
*/
|
||||
protected function createAccessDeniedException(string $message = 'Access Denied.', ?\Throwable $previous = null): AccessDeniedException
|
||||
{
|
||||
if (!class_exists(AccessDeniedException::class)) {
|
||||
throw new \LogicException('You cannot use the "createAccessDeniedException" method if the Security component is not available. Try running "composer require symfony/security-bundle".');
|
||||
}
|
||||
|
||||
return new AccessDeniedException($message, $previous);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a Form instance from the type of the form.
|
||||
*/
|
||||
protected function createForm(string $type, mixed $data = null, array $options = []): FormInterface
|
||||
{
|
||||
return $this->container->get('form.factory')->create($type, $data, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a form builder instance.
|
||||
*/
|
||||
protected function createFormBuilder(mixed $data = null, array $options = []): FormBuilderInterface
|
||||
{
|
||||
return $this->container->get('form.factory')->createBuilder(FormType::class, $data, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a user from the Security Token Storage.
|
||||
*
|
||||
* @throws \LogicException If SecurityBundle is not available
|
||||
*
|
||||
* @see TokenInterface::getUser()
|
||||
*/
|
||||
protected function getUser(): ?UserInterface
|
||||
{
|
||||
if (!$this->container->has('security.token_storage')) {
|
||||
throw new \LogicException('The SecurityBundle is not registered in your application. Try running "composer require symfony/security-bundle".');
|
||||
}
|
||||
|
||||
if (null === $token = $this->container->get('security.token_storage')->getToken()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $token->getUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the validity of a CSRF token.
|
||||
*
|
||||
* @param string $id The id used when generating the token
|
||||
* @param string|null $token The actual token sent with the request that should be validated
|
||||
*/
|
||||
protected function isCsrfTokenValid(string $id, #[\SensitiveParameter] ?string $token): bool
|
||||
{
|
||||
if (!$this->container->has('security.csrf.token_manager')) {
|
||||
throw new \LogicException('CSRF protection is not enabled in your application. Enable it with the "csrf_protection" key in "config/packages/framework.yaml".');
|
||||
}
|
||||
|
||||
return $this->container->get('security.csrf.token_manager')->isTokenValid(new CsrfToken($id, $token));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Link HTTP header to the current response.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc5988
|
||||
*/
|
||||
protected function addLink(Request $request, LinkInterface $link): void
|
||||
{
|
||||
if (!class_exists(AddLinkHeaderListener::class)) {
|
||||
throw new \LogicException('You cannot use the "addLink" method if the WebLink component is not available. Try running "composer require symfony/web-link".');
|
||||
}
|
||||
|
||||
if (null === $linkProvider = $request->attributes->get('_links')) {
|
||||
$request->attributes->set('_links', new GenericLinkProvider([$link]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$request->attributes->set('_links', $linkProvider->withLink($link));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LinkInterface[] $links
|
||||
*/
|
||||
protected function sendEarlyHints(iterable $links = [], ?Response $response = null): Response
|
||||
{
|
||||
if (!$this->container->has('web_link.http_header_serializer')) {
|
||||
throw new \LogicException('You cannot use the "sendEarlyHints" method if the WebLink component is not available. Try running "composer require symfony/web-link".');
|
||||
}
|
||||
|
||||
$response ??= new Response();
|
||||
|
||||
$populatedLinks = [];
|
||||
foreach ($links as $link) {
|
||||
if ($link instanceof EvolvableLinkInterface && !$link->getRels()) {
|
||||
$link = $link->withRel('preload');
|
||||
}
|
||||
|
||||
$populatedLinks[] = $link;
|
||||
}
|
||||
|
||||
$response->headers->set('Link', $this->container->get('web_link.http_header_serializer')->serialize($populatedLinks), false);
|
||||
$response->sendHeaders(103);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
private function doRenderView(string $view, ?string $block, array $parameters, string $method): string
|
||||
{
|
||||
if (!$this->container->has('twig')) {
|
||||
throw new \LogicException(\sprintf('You cannot use the "%s" method if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".', $method));
|
||||
}
|
||||
|
||||
foreach ($parameters as $k => $v) {
|
||||
if ($v instanceof FormInterface) {
|
||||
$parameters[$k] = $v->createView();
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $block) {
|
||||
return $this->container->get('twig')->load($view)->renderBlock($block, $parameters);
|
||||
}
|
||||
|
||||
return $this->container->get('twig')->render($view, $parameters);
|
||||
}
|
||||
|
||||
private function doRender(string $view, ?string $block, array $parameters, ?Response $response, string $method): Response
|
||||
{
|
||||
$content = $this->doRenderView($view, $block, $parameters, $method);
|
||||
$response ??= new Response();
|
||||
|
||||
if (200 === $response->getStatusCode()) {
|
||||
foreach ($parameters as $v) {
|
||||
if ($v instanceof FormInterface && $v->isSubmitted() && !$v->isValid()) {
|
||||
$response->setStatusCode(422);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response->setContent($content);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
37
vendor/symfony/framework-bundle/Controller/ControllerResolver.php
vendored
Normal file
37
vendor/symfony/framework-bundle/Controller/ControllerResolver.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?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\Bundle\FrameworkBundle\Controller;
|
||||
|
||||
use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class ControllerResolver extends ContainerControllerResolver
|
||||
{
|
||||
protected function instantiateController(string $class): object
|
||||
{
|
||||
$controller = parent::instantiateController($class);
|
||||
|
||||
if ($controller instanceof AbstractController) {
|
||||
if (null === $previousContainer = $controller->setContainer($this->container)) {
|
||||
throw new \LogicException(\sprintf('"%s" has no container set, did you forget to define it as a service subscriber?', $class));
|
||||
}
|
||||
|
||||
$controller->setContainer($previousContainer);
|
||||
}
|
||||
|
||||
return $controller;
|
||||
}
|
||||
}
|
||||
187
vendor/symfony/framework-bundle/Controller/RedirectController.php
vendored
Normal file
187
vendor/symfony/framework-bundle/Controller/RedirectController.php
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
<?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\Bundle\FrameworkBundle\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\HeaderUtils;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
|
||||
/**
|
||||
* Redirects a request to another URL.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RedirectController
|
||||
{
|
||||
public function __construct(
|
||||
private ?UrlGeneratorInterface $router = null,
|
||||
private ?int $httpPort = null,
|
||||
private ?int $httpsPort = null,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects to another route with the given name.
|
||||
*
|
||||
* The response status code is 302 if the permanent parameter is false (default),
|
||||
* and 301 if the redirection is permanent.
|
||||
*
|
||||
* In case the route name is empty, the status code will be 404 when permanent is false
|
||||
* and 410 otherwise.
|
||||
*
|
||||
* @param string $route The route name to redirect to
|
||||
* @param bool $permanent Whether the redirection is permanent
|
||||
* @param bool|array $ignoreAttributes Whether to ignore attributes or an array of attributes to ignore
|
||||
* @param bool $keepRequestMethod Whether redirect action should keep HTTP request method
|
||||
*
|
||||
* @throws HttpException In case the route name is empty
|
||||
*/
|
||||
public function redirectAction(Request $request, string $route, bool $permanent = false, bool|array $ignoreAttributes = false, bool $keepRequestMethod = false, bool $keepQueryParams = false): Response
|
||||
{
|
||||
if ('' == $route) {
|
||||
throw new HttpException($permanent ? 410 : 404);
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
if (false === $ignoreAttributes || \is_array($ignoreAttributes)) {
|
||||
$attributes = $request->attributes->get('_route_params');
|
||||
|
||||
if ($keepQueryParams) {
|
||||
if ($query = $request->server->get('QUERY_STRING')) {
|
||||
$query = HeaderUtils::parseQuery($query);
|
||||
} else {
|
||||
$query = $request->query->all();
|
||||
}
|
||||
|
||||
$attributes = array_merge($query, $attributes);
|
||||
}
|
||||
|
||||
unset($attributes['route'], $attributes['permanent'], $attributes['ignoreAttributes'], $attributes['keepRequestMethod'], $attributes['keepQueryParams']);
|
||||
if ($ignoreAttributes) {
|
||||
$attributes = array_diff_key($attributes, array_flip($ignoreAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
if ($keepRequestMethod) {
|
||||
$statusCode = $permanent ? 308 : 307;
|
||||
} else {
|
||||
$statusCode = $permanent ? 301 : 302;
|
||||
}
|
||||
|
||||
return new RedirectResponse($this->router->generate($route, $attributes, UrlGeneratorInterface::ABSOLUTE_URL), $statusCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects to a URL.
|
||||
*
|
||||
* The response status code is 302 if the permanent parameter is false (default),
|
||||
* and 301 if the redirection is permanent.
|
||||
*
|
||||
* In case the path is empty, the status code will be 404 when permanent is false
|
||||
* and 410 otherwise.
|
||||
*
|
||||
* @param string $path The absolute path or URL to redirect to
|
||||
* @param bool $permanent Whether the redirect is permanent or not
|
||||
* @param string|null $scheme The URL scheme (null to keep the current one)
|
||||
* @param int|null $httpPort The HTTP port (null to keep the current one for the same scheme or the default configured port)
|
||||
* @param int|null $httpsPort The HTTPS port (null to keep the current one for the same scheme or the default configured port)
|
||||
* @param bool $keepRequestMethod Whether redirect action should keep HTTP request method
|
||||
*
|
||||
* @throws HttpException In case the path is empty
|
||||
*/
|
||||
public function urlRedirectAction(Request $request, string $path, bool $permanent = false, ?string $scheme = null, ?int $httpPort = null, ?int $httpsPort = null, bool $keepRequestMethod = false): Response
|
||||
{
|
||||
if ('' === $path) {
|
||||
throw new HttpException($permanent ? 410 : 404);
|
||||
}
|
||||
|
||||
if ($keepRequestMethod) {
|
||||
$statusCode = $permanent ? 308 : 307;
|
||||
} else {
|
||||
$statusCode = $permanent ? 301 : 302;
|
||||
}
|
||||
|
||||
$scheme ??= $request->getScheme();
|
||||
|
||||
if (str_starts_with($path, '//')) {
|
||||
$path = $scheme.':'.$path;
|
||||
}
|
||||
|
||||
// redirect if the path is a full URL
|
||||
if (parse_url($path, \PHP_URL_SCHEME)) {
|
||||
return new RedirectResponse($path, $statusCode);
|
||||
}
|
||||
|
||||
if ($qs = $request->server->get('QUERY_STRING') ?: $request->getQueryString()) {
|
||||
if (!str_contains($path, '?')) {
|
||||
$qs = '?'.$qs;
|
||||
} else {
|
||||
$qs = '&'.$qs;
|
||||
}
|
||||
}
|
||||
|
||||
$port = '';
|
||||
if ('http' === $scheme) {
|
||||
if (null === $httpPort) {
|
||||
if ('http' === $request->getScheme()) {
|
||||
$httpPort = $request->getPort();
|
||||
} else {
|
||||
$httpPort = $this->httpPort;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $httpPort && 80 != $httpPort) {
|
||||
$port = ":$httpPort";
|
||||
}
|
||||
} elseif ('https' === $scheme) {
|
||||
if (null === $httpsPort) {
|
||||
if ('https' === $request->getScheme()) {
|
||||
$httpsPort = $request->getPort();
|
||||
} else {
|
||||
$httpsPort = $this->httpsPort;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $httpsPort && 443 != $httpsPort) {
|
||||
$port = ":$httpsPort";
|
||||
}
|
||||
}
|
||||
|
||||
$url = $scheme.'://'.$request->getHost().$port.$request->getBaseUrl().$path.$qs;
|
||||
|
||||
return new RedirectResponse($url, $statusCode);
|
||||
}
|
||||
|
||||
public function __invoke(Request $request): Response
|
||||
{
|
||||
$p = $request->attributes->get('_route_params', []);
|
||||
|
||||
if (\array_key_exists('route', $p)) {
|
||||
if (\array_key_exists('path', $p)) {
|
||||
throw new \RuntimeException(\sprintf('Ambiguous redirection settings, use the "path" or "route" parameter, not both: "%s" and "%s" found respectively in "%s" routing configuration.', $p['path'], $p['route'], $request->attributes->get('_route')));
|
||||
}
|
||||
|
||||
return $this->redirectAction($request, $p['route'], $p['permanent'] ?? false, $p['ignoreAttributes'] ?? false, $p['keepRequestMethod'] ?? false, $p['keepQueryParams'] ?? false);
|
||||
}
|
||||
|
||||
if (\array_key_exists('path', $p)) {
|
||||
return $this->urlRedirectAction($request, $p['path'], $p['permanent'] ?? false, $p['scheme'] ?? null, $p['httpPort'] ?? null, $p['httpsPort'] ?? null, $p['keepRequestMethod'] ?? false);
|
||||
}
|
||||
|
||||
throw new \RuntimeException(\sprintf('The parameter "path" or "route" is required to configure the redirect action in "%s" routing configuration.', $request->attributes->get('_route')));
|
||||
}
|
||||
}
|
||||
78
vendor/symfony/framework-bundle/Controller/TemplateController.php
vendored
Normal file
78
vendor/symfony/framework-bundle/Controller/TemplateController.php
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
<?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\Bundle\FrameworkBundle\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Twig\Environment;
|
||||
|
||||
/**
|
||||
* TemplateController.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class TemplateController
|
||||
{
|
||||
public function __construct(
|
||||
private ?Environment $twig = null,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a template.
|
||||
*
|
||||
* @param string $template The template name
|
||||
* @param int|null $maxAge Max age for client caching
|
||||
* @param int|null $sharedAge Max age for shared (proxy) caching
|
||||
* @param bool|null $private Whether or not caching should apply for client caches only
|
||||
* @param array $context The context (arguments) of the template
|
||||
* @param int $statusCode The HTTP status code to return with the response (200 "OK" by default)
|
||||
* @param array $headers The HTTP headers to add to the response
|
||||
*/
|
||||
public function templateAction(string $template, ?int $maxAge = null, ?int $sharedAge = null, ?bool $private = null, array $context = [], int $statusCode = 200, array $headers = []): Response
|
||||
{
|
||||
if (null === $this->twig) {
|
||||
throw new \LogicException('You cannot use the TemplateController if the Twig Bundle is not available. Try running "composer require symfony/twig-bundle".');
|
||||
}
|
||||
|
||||
$response = new Response($this->twig->render($template, $context), $statusCode);
|
||||
|
||||
if ($maxAge) {
|
||||
$response->setMaxAge($maxAge);
|
||||
}
|
||||
|
||||
if (null !== $sharedAge) {
|
||||
$response->setSharedMaxAge($sharedAge);
|
||||
}
|
||||
|
||||
if ($private) {
|
||||
$response->setPrivate();
|
||||
} elseif (false === $private || (null === $private && (null !== $maxAge || null !== $sharedAge))) {
|
||||
$response->setPublic();
|
||||
}
|
||||
|
||||
foreach ($headers as $key => $value) {
|
||||
$response->headers->set($key, $value);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $statusCode The HTTP status code (200 "OK" by default)
|
||||
*/
|
||||
public function __invoke(string $template, ?int $maxAge = null, ?int $sharedAge = null, ?bool $private = null, array $context = [], int $statusCode = 200, array $headers = []): Response
|
||||
{
|
||||
return $this->templateAction($template, $maxAge, $sharedAge, $private, $context, $statusCode, $headers);
|
||||
}
|
||||
}
|
||||
30
vendor/symfony/framework-bundle/DataCollector/AbstractDataCollector.php
vendored
Normal file
30
vendor/symfony/framework-bundle/DataCollector/AbstractDataCollector.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?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\Bundle\FrameworkBundle\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
|
||||
|
||||
/**
|
||||
* @author Laurent VOULLEMIER <laurent.voullemier@gmail.com>
|
||||
*/
|
||||
abstract class AbstractDataCollector extends DataCollector implements TemplateAwareDataCollectorInterface
|
||||
{
|
||||
public function getName(): string
|
||||
{
|
||||
return static::class;
|
||||
}
|
||||
|
||||
public static function getTemplate(): ?string
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
37
vendor/symfony/framework-bundle/DataCollector/RouterDataCollector.php
vendored
Normal file
37
vendor/symfony/framework-bundle/DataCollector/RouterDataCollector.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?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\Bundle\FrameworkBundle\DataCollector;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\RedirectController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\DataCollector\RouterDataCollector as BaseRouterDataCollector;
|
||||
|
||||
/**
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RouterDataCollector extends BaseRouterDataCollector
|
||||
{
|
||||
public function guessRoute(Request $request, mixed $controller): string
|
||||
{
|
||||
if (\is_array($controller)) {
|
||||
$controller = $controller[0];
|
||||
}
|
||||
|
||||
if ($controller instanceof RedirectController && $request->attributes->has('_route')) {
|
||||
return $request->attributes->get('_route');
|
||||
}
|
||||
|
||||
return parent::guessRoute($request, $controller);
|
||||
}
|
||||
}
|
||||
22
vendor/symfony/framework-bundle/DataCollector/TemplateAwareDataCollectorInterface.php
vendored
Normal file
22
vendor/symfony/framework-bundle/DataCollector/TemplateAwareDataCollectorInterface.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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\Bundle\FrameworkBundle\DataCollector;
|
||||
|
||||
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
|
||||
|
||||
/**
|
||||
* @author Laurent VOULLEMIER <laurent.voullemier@gmail.com>
|
||||
*/
|
||||
interface TemplateAwareDataCollectorInterface extends DataCollectorInterface
|
||||
{
|
||||
public static function getTemplate(): ?string;
|
||||
}
|
||||
35
vendor/symfony/framework-bundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php
vendored
Normal file
35
vendor/symfony/framework-bundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php
vendored
Normal file
@@ -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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
class AddDebugLogProcessorPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('profiler')) {
|
||||
return;
|
||||
}
|
||||
if (!$container->hasDefinition('monolog.logger_prototype')) {
|
||||
return;
|
||||
}
|
||||
if (!$container->hasDefinition('debug.log_processor')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$container->getDefinition('monolog.logger_prototype')
|
||||
->setConfigurator([new Reference('debug.debug_logger_configurator'), 'pushDebugLogger']);
|
||||
}
|
||||
}
|
||||
44
vendor/symfony/framework-bundle/DependencyInjection/Compiler/AssetsContextPass.php
vendored
Normal file
44
vendor/symfony/framework-bundle/DependencyInjection/Compiler/AssetsContextPass.php
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
class AssetsContextPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('assets.context')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$container->hasDefinition('router.request_context')) {
|
||||
$container->setParameter('asset.request_context.base_path', $container->getParameter('asset.request_context.base_path') ?? '');
|
||||
$container->setParameter('asset.request_context.secure', $container->getParameter('asset.request_context.secure') ?? false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$context = $container->getDefinition('assets.context');
|
||||
|
||||
if (null === $container->getParameter('asset.request_context.base_path')) {
|
||||
$context->replaceArgument(1, (new Definition('string'))->setFactory([new Reference('router.request_context'), 'getBaseUrl']));
|
||||
}
|
||||
|
||||
if (null === $container->getParameter('asset.request_context.secure')) {
|
||||
$context->replaceArgument(2, (new Definition('bool'))->setFactory([new Reference('router.request_context'), 'isSecure']));
|
||||
}
|
||||
}
|
||||
}
|
||||
39
vendor/symfony/framework-bundle/DependencyInjection/Compiler/ContainerBuilderDebugDumpPass.php
vendored
Normal file
39
vendor/symfony/framework-bundle/DependencyInjection/Compiler/ContainerBuilderDebugDumpPass.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\Config\ConfigCache;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Dumper\XmlDumper;
|
||||
|
||||
/**
|
||||
* Dumps the ContainerBuilder to a cache file so that it can be used by
|
||||
* debugging tools such as the debug:container console command.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@thatsquality.com>
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ContainerBuilderDebugDumpPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->getParameter('debug.container.dump')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$cache = new ConfigCache($container->getParameter('debug.container.dump'), true);
|
||||
if (!$cache->isFresh()) {
|
||||
$cache->write((new XmlDumper($container))->dump(), $container->getResources());
|
||||
}
|
||||
}
|
||||
}
|
||||
37
vendor/symfony/framework-bundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php
vendored
Normal file
37
vendor/symfony/framework-bundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
class ErrorLoggerCompilerPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('debug.error_handler_configurator')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$definition = $container->getDefinition('debug.error_handler_configurator');
|
||||
if ($container->hasDefinition('monolog.logger.php')) {
|
||||
$definition->replaceArgument(0, new Reference('monolog.logger.php'));
|
||||
}
|
||||
if ($container->hasDefinition('monolog.logger.deprecation')) {
|
||||
$definition->replaceArgument(5, new Reference('monolog.logger.deprecation'));
|
||||
}
|
||||
}
|
||||
}
|
||||
61
vendor/symfony/framework-bundle/DependencyInjection/Compiler/ProfilerPass.php
vendored
Normal file
61
vendor/symfony/framework-bundle/DependencyInjection/Compiler/ProfilerPass.php
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\DataCollector\TemplateAwareDataCollectorInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* Adds tagged data_collector services to profiler service.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class ProfilerPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (false === $container->hasDefinition('profiler')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$definition = $container->getDefinition('profiler');
|
||||
|
||||
$collectors = new \SplPriorityQueue();
|
||||
$order = \PHP_INT_MAX;
|
||||
foreach ($container->findTaggedServiceIds('data_collector', true) as $id => $attributes) {
|
||||
$priority = $attributes[0]['priority'] ?? 0;
|
||||
$template = null;
|
||||
|
||||
$collectorClass = $container->findDefinition($id)->getClass();
|
||||
if (isset($attributes[0]['template']) || is_subclass_of($collectorClass, TemplateAwareDataCollectorInterface::class)) {
|
||||
$idForTemplate = $attributes[0]['id'] ?? $collectorClass;
|
||||
if (!$idForTemplate) {
|
||||
throw new InvalidArgumentException(\sprintf('Data collector service "%s" must have an id attribute in order to specify a template.', $id));
|
||||
}
|
||||
$template = [$idForTemplate, $attributes[0]['template'] ?? $collectorClass::getTemplate()];
|
||||
}
|
||||
|
||||
$collectors->insert([$id, $template], [$priority, --$order]);
|
||||
}
|
||||
|
||||
$templates = [];
|
||||
foreach ($collectors as $collector) {
|
||||
$definition->addMethodCall('add', [new Reference($collector[0])]);
|
||||
$templates[$collector[0]] = $collector[1];
|
||||
}
|
||||
|
||||
$container->setParameter('data_collector.templates', $templates);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* @author Ahmed TAILOULOUTE <ahmed.tailouloute@gmail.com>
|
||||
*/
|
||||
class RemoveUnusedSessionMarshallingHandlerPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('session.marshalling_handler')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$isMarshallerDecorated = false;
|
||||
|
||||
foreach ($container->getDefinitions() as $definition) {
|
||||
$decorated = $definition->getDecoratedService();
|
||||
if (null !== $decorated && 'session.marshaller' === $decorated[0]) {
|
||||
$isMarshallerDecorated = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$isMarshallerDecorated) {
|
||||
$container->removeDefinition('session.marshalling_handler');
|
||||
}
|
||||
}
|
||||
}
|
||||
67
vendor/symfony/framework-bundle/DependencyInjection/Compiler/TestServiceContainerRealRefPass.php
vendored
Normal file
67
vendor/symfony/framework-bundle/DependencyInjection/Compiler/TestServiceContainerRealRefPass.php
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class TestServiceContainerRealRefPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('test.private_services_locator')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$privateContainer = $container->getDefinition('test.private_services_locator');
|
||||
$definitions = $container->getDefinitions();
|
||||
$privateServices = $privateContainer->getArgument(0);
|
||||
$renamedIds = [];
|
||||
|
||||
foreach ($privateServices as $id => $argument) {
|
||||
if (isset($definitions[$target = (string) $argument->getValues()[0]])) {
|
||||
$argument->setValues([new Reference($target)]);
|
||||
if ($id !== $target) {
|
||||
$renamedIds[$id] = $target;
|
||||
}
|
||||
if ($inner = $definitions[$target]->getTag('container.decorator')[0]['inner'] ?? null) {
|
||||
$renamedIds[$id] = $inner;
|
||||
}
|
||||
} else {
|
||||
unset($privateServices[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($container->getAliases() as $id => $target) {
|
||||
while ($container->hasAlias($target = (string) $target)) {
|
||||
$target = $container->getAlias($target);
|
||||
}
|
||||
|
||||
if ($definitions[$target]->hasTag('container.private')) {
|
||||
$privateServices[$id] = new ServiceClosureArgument(new Reference($target));
|
||||
}
|
||||
|
||||
$renamedIds[$id] = $target;
|
||||
}
|
||||
|
||||
$privateContainer->replaceArgument(0, $privateServices);
|
||||
|
||||
if ($container->hasDefinition('test.service_container') && $renamedIds) {
|
||||
$container->getDefinition('test.service_container')->setArgument(2, $renamedIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
58
vendor/symfony/framework-bundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php
vendored
Normal file
58
vendor/symfony/framework-bundle/DependencyInjection/Compiler/TestServiceContainerWeakRefPass.php
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
/**
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
class TestServiceContainerWeakRefPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('test.private_services_locator')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$privateServices = [];
|
||||
$definitions = $container->getDefinitions();
|
||||
|
||||
foreach ($definitions as $id => $definition) {
|
||||
if ($id && '.' !== $id[0] && (!$definition->isPublic() || $definition->isPrivate() || $definition->hasTag('container.private')) && !$definition->hasErrors() && !$definition->isAbstract()) {
|
||||
$privateServices[$id] = new Reference($id, ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE);
|
||||
}
|
||||
}
|
||||
|
||||
$aliases = $container->getAliases();
|
||||
|
||||
foreach ($aliases as $id => $alias) {
|
||||
if ($id && '.' !== $id[0] && (!$alias->isPublic() || $alias->isPrivate())) {
|
||||
while (isset($aliases[$target = (string) $alias])) {
|
||||
$alias = $aliases[$target];
|
||||
}
|
||||
if (isset($definitions[$target]) && !$definitions[$target]->hasErrors() && !$definitions[$target]->isAbstract()) {
|
||||
$privateServices[$id] = new Reference($target, ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($privateServices) {
|
||||
$id = (string) ServiceLocatorTagPass::register($container, $privateServices);
|
||||
$container->setDefinition('test.private_services_locator', $container->getDefinition($id))->setPublic(true);
|
||||
$container->removeDefinition($id);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
vendor/symfony/framework-bundle/DependencyInjection/Compiler/TranslationLintCommandPass.php
vendored
Normal file
33
vendor/symfony/framework-bundle/DependencyInjection/Compiler/TranslationLintCommandPass.php
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Translation\TranslatorBagInterface;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
final class TranslationLintCommandPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('console.command.translation_lint') || !$container->has('translator')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$translatorClass = $container->getParameterBag()->resolveValue($container->findDefinition('translator')->getClass());
|
||||
|
||||
if (!is_subclass_of($translatorClass, TranslatorInterface::class) || !is_subclass_of($translatorClass, TranslatorBagInterface::class)) {
|
||||
$container->removeDefinition('console.command.translation_lint');
|
||||
}
|
||||
}
|
||||
}
|
||||
31
vendor/symfony/framework-bundle/DependencyInjection/Compiler/TranslationUpdateCommandPass.php
vendored
Normal file
31
vendor/symfony/framework-bundle/DependencyInjection/Compiler/TranslationUpdateCommandPass.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
class TranslationUpdateCommandPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if (!$container->hasDefinition('console.command.translation_extract')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$translationWriterClass = $container->getParameterBag()->resolveValue($container->findDefinition('translation.writer')->getClass());
|
||||
|
||||
if (!method_exists($translationWriterClass, 'getFormats')) {
|
||||
$container->removeDefinition('console.command.translation_extract');
|
||||
}
|
||||
}
|
||||
}
|
||||
144
vendor/symfony/framework-bundle/DependencyInjection/Compiler/UnusedTagsPass.php
vendored
Normal file
144
vendor/symfony/framework-bundle/DependencyInjection/Compiler/UnusedTagsPass.php
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* Find all service tags which are defined, but not used and yield a warning log message.
|
||||
*
|
||||
* @author Florian Pfitzer <pfitzer@wurzel3.de>
|
||||
*/
|
||||
class UnusedTagsPass implements CompilerPassInterface
|
||||
{
|
||||
private const KNOWN_TAGS = [
|
||||
'asset_mapper.compiler',
|
||||
'assets.package',
|
||||
'auto_alias',
|
||||
'cache.pool',
|
||||
'cache.pool.clearer',
|
||||
'cache.taggable',
|
||||
'chatter.transport_factory',
|
||||
'config_cache.resource_checker',
|
||||
'console.command',
|
||||
'container.env_var_loader',
|
||||
'container.env_var_processor',
|
||||
'container.excluded',
|
||||
'container.hot_path',
|
||||
'container.no_preload',
|
||||
'container.preload',
|
||||
'container.private',
|
||||
'container.reversible',
|
||||
'container.service_locator',
|
||||
'container.service_locator_context',
|
||||
'container.service_subscriber',
|
||||
'container.stack',
|
||||
'controller.argument_value_resolver',
|
||||
'controller.service_arguments',
|
||||
'controller.targeted_value_resolver',
|
||||
'data_collector',
|
||||
'event_dispatcher.dispatcher',
|
||||
'form.type',
|
||||
'form.type_extension',
|
||||
'form.type_guesser',
|
||||
'html_sanitizer',
|
||||
'http_client.client',
|
||||
'json_streamer.value_transformer',
|
||||
'kernel.cache_clearer',
|
||||
'kernel.cache_warmer',
|
||||
'kernel.event_listener',
|
||||
'kernel.event_subscriber',
|
||||
'kernel.fragment_renderer',
|
||||
'kernel.locale_aware',
|
||||
'kernel.reset',
|
||||
'ldap',
|
||||
'mailer.transport_factory',
|
||||
'messenger.bus',
|
||||
'messenger.message_handler',
|
||||
'messenger.receiver',
|
||||
'messenger.transport_factory',
|
||||
'mime.mime_type_guesser',
|
||||
'monolog.logger',
|
||||
'notifier.channel',
|
||||
'property_info.access_extractor',
|
||||
'property_info.constructor_extractor',
|
||||
'property_info.initializable_extractor',
|
||||
'property_info.list_extractor',
|
||||
'property_info.type_extractor',
|
||||
'proxy',
|
||||
'remote_event.consumer',
|
||||
'routing.condition_service',
|
||||
'routing.expression_language_function',
|
||||
'routing.expression_language_provider',
|
||||
'routing.loader',
|
||||
'routing.route_loader',
|
||||
'scheduler.schedule_provider',
|
||||
'scheduler.task',
|
||||
'security.access_token_handler.oidc.encryption_algorithm',
|
||||
'security.access_token_handler.oidc.signature_algorithm',
|
||||
'security.authenticator.login_linker',
|
||||
'security.expression_language_provider',
|
||||
'security.remember_me_handler',
|
||||
'security.voter',
|
||||
'serializer.encoder',
|
||||
'serializer.normalizer',
|
||||
'texter.transport_factory',
|
||||
'translation.dumper',
|
||||
'translation.extractor',
|
||||
'translation.extractor.visitor',
|
||||
'translation.loader',
|
||||
'translation.provider_factory',
|
||||
'twig.extension',
|
||||
'twig.loader',
|
||||
'twig.runtime',
|
||||
'validator.auto_mapper',
|
||||
'validator.constraint_validator',
|
||||
'validator.group_provider',
|
||||
'validator.initializer',
|
||||
'workflow',
|
||||
'object_mapper.transform_callable',
|
||||
'object_mapper.condition_callable',
|
||||
];
|
||||
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$tags = array_unique(array_merge($container->findTags(), self::KNOWN_TAGS));
|
||||
|
||||
foreach ($container->findUnusedTags() as $tag) {
|
||||
// skip known tags
|
||||
if (\in_array($tag, self::KNOWN_TAGS, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for typos
|
||||
$candidates = [];
|
||||
foreach ($tags as $definedTag) {
|
||||
if ($definedTag === $tag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str_contains($definedTag, $tag) || levenshtein($tag, $definedTag) <= \strlen($tag) / 3) {
|
||||
$candidates[] = $definedTag;
|
||||
}
|
||||
}
|
||||
|
||||
$services = array_keys($container->findTaggedServiceIds($tag));
|
||||
$message = \sprintf('Tag "%s" was defined on service(s) "%s", but was never used.', $tag, implode('", "', $services));
|
||||
if ($candidates) {
|
||||
$message .= \sprintf(' Did you mean "%s"?', implode('", "', $candidates));
|
||||
}
|
||||
|
||||
$container->log($this, $message);
|
||||
}
|
||||
}
|
||||
}
|
||||
2765
vendor/symfony/framework-bundle/DependencyInjection/Configuration.php
vendored
Normal file
2765
vendor/symfony/framework-bundle/DependencyInjection/Configuration.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3499
vendor/symfony/framework-bundle/DependencyInjection/FrameworkExtension.php
vendored
Normal file
3499
vendor/symfony/framework-bundle/DependencyInjection/FrameworkExtension.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
34
vendor/symfony/framework-bundle/DependencyInjection/VirtualRequestStackPass.php
vendored
Normal file
34
vendor/symfony/framework-bundle/DependencyInjection/VirtualRequestStackPass.php
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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\Bundle\FrameworkBundle\DependencyInjection;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
|
||||
class VirtualRequestStackPass implements CompilerPassInterface
|
||||
{
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
if ($container->has('.virtual_request_stack')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($container->hasDefinition('debug.event_dispatcher')) {
|
||||
$container->getDefinition('debug.event_dispatcher')->replaceArgument(3, new Reference('request_stack', ContainerBuilder::NULL_ON_INVALID_REFERENCE));
|
||||
}
|
||||
|
||||
if ($container->hasDefinition('debug.log_processor')) {
|
||||
$container->getDefinition('debug.log_processor')->replaceArgument(0, new Reference('request_stack'));
|
||||
}
|
||||
}
|
||||
}
|
||||
166
vendor/symfony/framework-bundle/EventListener/ConsoleProfilerListener.php
vendored
Normal file
166
vendor/symfony/framework-bundle/EventListener/ConsoleProfilerListener.php
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
<?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\Bundle\FrameworkBundle\EventListener;
|
||||
|
||||
use Symfony\Component\Console\ConsoleEvents;
|
||||
use Symfony\Component\Console\Debug\CliRequest;
|
||||
use Symfony\Component\Console\Event\ConsoleCommandEvent;
|
||||
use Symfony\Component\Console\Event\ConsoleErrorEvent;
|
||||
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
|
||||
use Symfony\Component\Console\Output\ConsoleOutputInterface;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profile;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profiler;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Stopwatch\Stopwatch;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* @author Jules Pietri <jules@heahprod.com>
|
||||
*/
|
||||
final class ConsoleProfilerListener implements EventSubscriberInterface
|
||||
{
|
||||
private ?\Throwable $error = null;
|
||||
/** @var \SplObjectStorage<Request, Profile> */
|
||||
private \SplObjectStorage $profiles;
|
||||
/** @var \SplObjectStorage<Request, ?Request> */
|
||||
private \SplObjectStorage $parents;
|
||||
|
||||
private bool $disabled = false;
|
||||
|
||||
public function __construct(
|
||||
private readonly Profiler $profiler,
|
||||
private readonly RequestStack $requestStack,
|
||||
private readonly Stopwatch $stopwatch,
|
||||
private readonly bool $cliMode,
|
||||
private readonly ?UrlGeneratorInterface $urlGenerator = null,
|
||||
) {
|
||||
$this->profiles = new \SplObjectStorage();
|
||||
$this->parents = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
ConsoleEvents::COMMAND => ['initialize', 4096],
|
||||
ConsoleEvents::ERROR => ['catch', -2048],
|
||||
ConsoleEvents::TERMINATE => ['profile', -4096],
|
||||
];
|
||||
}
|
||||
|
||||
public function initialize(ConsoleCommandEvent $event): void
|
||||
{
|
||||
if (!$this->cliMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
$input = $event->getInput();
|
||||
if (!$input->hasOption('profile') || !$input->getOption('profile')) {
|
||||
$this->disabled = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
|
||||
if (!$request instanceof CliRequest || $request->command !== $event->getCommand()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$request->attributes->set('_stopwatch_token', bin2hex(random_bytes(3)));
|
||||
$this->stopwatch->openSection();
|
||||
}
|
||||
|
||||
public function catch(ConsoleErrorEvent $event): void
|
||||
{
|
||||
if (!$this->cliMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->error = $event->getError();
|
||||
}
|
||||
|
||||
public function profile(ConsoleTerminateEvent $event): void
|
||||
{
|
||||
$error = $this->error;
|
||||
$this->error = null;
|
||||
|
||||
if (!$this->cliMode || $this->disabled) {
|
||||
$this->disabled = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$request = $this->requestStack->getCurrentRequest();
|
||||
|
||||
if (!$request instanceof CliRequest || $request->command !== $event->getCommand()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$this->profiler->isEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (null !== $sectionId = $request->attributes->get('_stopwatch_token')) {
|
||||
// we must close the section before saving the profile to allow late collect
|
||||
try {
|
||||
$this->stopwatch->stopSection($sectionId);
|
||||
} catch (\LogicException) {
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
$request->command->exitCode = $event->getExitCode();
|
||||
$request->command->interruptedBySignal = $event->getInterruptingSignal();
|
||||
|
||||
$profile = $this->profiler->collect($request, $request->getResponse(), $error);
|
||||
$this->profiles[$request] = $profile;
|
||||
|
||||
if ($this->parents[$request] = $this->requestStack->getParentRequest()) {
|
||||
// do not save on sub commands
|
||||
return;
|
||||
}
|
||||
|
||||
// attach children to parents
|
||||
foreach ($this->profiles as $request) {
|
||||
if (null !== $parentRequest = $this->parents[$request]) {
|
||||
if (isset($this->profiles[$parentRequest])) {
|
||||
$this->profiles[$parentRequest]->addChild($this->profiles[$request]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$output = $event->getOutput();
|
||||
$output = $output instanceof ConsoleOutputInterface && $output->isVerbose() ? $output->getErrorOutput() : null;
|
||||
|
||||
// save profiles
|
||||
foreach ($this->profiles as $r) {
|
||||
$p = $this->profiles[$r];
|
||||
$this->profiler->saveProfile($p);
|
||||
|
||||
if ($this->urlGenerator && $output) {
|
||||
$token = $p->getToken();
|
||||
$output->writeln(\sprintf(
|
||||
'See profile <href=%s>%s</>',
|
||||
$this->urlGenerator->generate('_profiler', ['token' => $token], UrlGeneratorInterface::ABSOLUTE_URL),
|
||||
$token
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$this->profiles = new \SplObjectStorage();
|
||||
$this->parents = new \SplObjectStorage();
|
||||
}
|
||||
}
|
||||
79
vendor/symfony/framework-bundle/EventListener/SuggestMissingPackageSubscriber.php
vendored
Normal file
79
vendor/symfony/framework-bundle/EventListener/SuggestMissingPackageSubscriber.php
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
<?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\Bundle\FrameworkBundle\EventListener;
|
||||
|
||||
use Symfony\Component\Console\ConsoleEvents;
|
||||
use Symfony\Component\Console\Event\ConsoleErrorEvent;
|
||||
use Symfony\Component\Console\Exception\CommandNotFoundException;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
/**
|
||||
* Suggests a package, that should be installed (via composer),
|
||||
* if the package is missing, and the input command namespace can be mapped to a Symfony bundle.
|
||||
*
|
||||
* @author Przemysław Bogusz <przemyslaw.bogusz@tubotax.pl>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class SuggestMissingPackageSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
private const PACKAGES = [
|
||||
'doctrine' => [
|
||||
'fixtures' => ['DoctrineFixturesBundle', 'doctrine/doctrine-fixtures-bundle --dev'],
|
||||
'mongodb' => ['DoctrineMongoDBBundle', 'doctrine/mongodb-odm-bundle'],
|
||||
'_default' => ['Doctrine ORM', 'symfony/orm-pack'],
|
||||
],
|
||||
'make' => [
|
||||
'_default' => ['MakerBundle', 'symfony/maker-bundle --dev'],
|
||||
],
|
||||
'server' => [
|
||||
'_default' => ['Debug Bundle', 'symfony/debug-bundle --dev'],
|
||||
],
|
||||
];
|
||||
|
||||
public function onConsoleError(ConsoleErrorEvent $event): void
|
||||
{
|
||||
if (!$event->getError() instanceof CommandNotFoundException) {
|
||||
return;
|
||||
}
|
||||
|
||||
[$namespace, $command] = explode(':', $event->getInput()->getFirstArgument()) + [1 => ''];
|
||||
|
||||
if (!isset(self::PACKAGES[$namespace])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset(self::PACKAGES[$namespace][$command])) {
|
||||
$suggestion = self::PACKAGES[$namespace][$command];
|
||||
$exact = true;
|
||||
} else {
|
||||
$suggestion = self::PACKAGES[$namespace]['_default'];
|
||||
$exact = false;
|
||||
}
|
||||
|
||||
$error = $event->getError();
|
||||
|
||||
if ($error->getAlternatives() && !$exact) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = \sprintf("%s\n\nYou may be looking for a command provided by the \"%s\" which is currently not installed. Try running \"composer require %s\".", $error->getMessage(), $suggestion[0], $suggestion[1]);
|
||||
$event->setError(new CommandNotFoundException($message));
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
ConsoleEvents::ERROR => ['onConsoleError', 0],
|
||||
];
|
||||
}
|
||||
}
|
||||
222
vendor/symfony/framework-bundle/FrameworkBundle.php
vendored
Normal file
222
vendor/symfony/framework-bundle/FrameworkBundle.php
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
<?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\Bundle\FrameworkBundle;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddDebugLogProcessorPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AssetsContextPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilderDebugDumpPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ErrorLoggerCompilerPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RemoveUnusedSessionMarshallingHandlerPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerRealRefPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerWeakRefPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationLintCommandPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationUpdateCommandPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;
|
||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\VirtualRequestStackPass;
|
||||
use Symfony\Component\Cache\Adapter\ApcuAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ChainAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PhpArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PhpFilesAdapter;
|
||||
use Symfony\Component\Cache\DependencyInjection\CacheCollectorPass;
|
||||
use Symfony\Component\Cache\DependencyInjection\CachePoolClearerPass;
|
||||
use Symfony\Component\Cache\DependencyInjection\CachePoolPass;
|
||||
use Symfony\Component\Cache\DependencyInjection\CachePoolPrunerPass;
|
||||
use Symfony\Component\Config\Resource\ClassExistenceResource;
|
||||
use Symfony\Component\Console\ConsoleEvents;
|
||||
use Symfony\Component\Console\DependencyInjection\AddConsoleCommandPass;
|
||||
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
|
||||
use Symfony\Component\DependencyInjection\Compiler\RegisterReverseContainerPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
use Symfony\Component\ErrorHandler\ErrorHandler;
|
||||
use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass;
|
||||
use Symfony\Component\Form\DependencyInjection\FormPass;
|
||||
use Symfony\Component\HttpClient\DependencyInjection\HttpClientPass;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\ControllerArgumentValueResolverPass;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\FragmentRendererPass;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\LoggerPass;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\RegisterLocaleAwareServicesPass;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
use Symfony\Component\JsonStreamer\DependencyInjection\StreamablePass;
|
||||
use Symfony\Component\Messenger\DependencyInjection\MessengerPass;
|
||||
use Symfony\Component\Mime\DependencyInjection\AddMimeTypeGuesserPass;
|
||||
use Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoConstructorPass;
|
||||
use Symfony\Component\PropertyInfo\DependencyInjection\PropertyInfoPass;
|
||||
use Symfony\Component\Routing\DependencyInjection\AddExpressionLanguageProvidersPass;
|
||||
use Symfony\Component\Routing\DependencyInjection\RoutingResolverPass;
|
||||
use Symfony\Component\Runtime\SymfonyRuntime;
|
||||
use Symfony\Component\Scheduler\DependencyInjection\AddScheduleMessengerPass;
|
||||
use Symfony\Component\Serializer\DependencyInjection\SerializerPass;
|
||||
use Symfony\Component\Translation\DependencyInjection\DataCollectorTranslatorPass;
|
||||
use Symfony\Component\Translation\DependencyInjection\LoggingTranslatorPass;
|
||||
use Symfony\Component\Translation\DependencyInjection\TranslationDumperPass;
|
||||
use Symfony\Component\Translation\DependencyInjection\TranslationExtractorPass;
|
||||
use Symfony\Component\Translation\DependencyInjection\TranslatorPass;
|
||||
use Symfony\Component\Translation\DependencyInjection\TranslatorPathsPass;
|
||||
use Symfony\Component\Validator\DependencyInjection\AddAutoMappingConfigurationPass;
|
||||
use Symfony\Component\Validator\DependencyInjection\AddConstraintValidatorsPass;
|
||||
use Symfony\Component\Validator\DependencyInjection\AddValidatorInitializersPass;
|
||||
use Symfony\Component\VarExporter\Internal\Hydrator;
|
||||
use Symfony\Component\VarExporter\Internal\Registry;
|
||||
use Symfony\Component\Workflow\DependencyInjection\WorkflowDebugPass;
|
||||
use Symfony\Component\Workflow\DependencyInjection\WorkflowGuardListenerPass;
|
||||
use Symfony\Component\Workflow\DependencyInjection\WorkflowValidatorPass;
|
||||
|
||||
// Help opcache.preload discover always-needed symbols
|
||||
class_exists(ApcuAdapter::class);
|
||||
class_exists(ArrayAdapter::class);
|
||||
class_exists(ChainAdapter::class);
|
||||
class_exists(PhpArrayAdapter::class);
|
||||
class_exists(PhpFilesAdapter::class);
|
||||
class_exists(Dotenv::class);
|
||||
class_exists(ErrorHandler::class);
|
||||
class_exists(Hydrator::class);
|
||||
class_exists(Registry::class);
|
||||
|
||||
/**
|
||||
* Bundle.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class FrameworkBundle extends Bundle
|
||||
{
|
||||
public function boot(): void
|
||||
{
|
||||
$_ENV['DOCTRINE_DEPRECATIONS'] = $_SERVER['DOCTRINE_DEPRECATIONS'] ??= 'trigger';
|
||||
|
||||
if (class_exists(SymfonyRuntime::class)) {
|
||||
$handler = set_error_handler('var_dump');
|
||||
restore_error_handler();
|
||||
} else {
|
||||
$handler = [ErrorHandler::register(null, false)];
|
||||
}
|
||||
|
||||
if (\is_array($handler) && $handler[0] instanceof ErrorHandler) {
|
||||
$this->container->get('debug.error_handler_configurator')->configure($handler[0]);
|
||||
}
|
||||
|
||||
if ($this->container->getParameter('kernel.http_method_override')) {
|
||||
Request::enableHttpMethodParameterOverride();
|
||||
}
|
||||
|
||||
if ($this->container->hasParameter('kernel.trust_x_sendfile_type_header') && $this->container->getParameter('kernel.trust_x_sendfile_type_header')) {
|
||||
BinaryFileResponse::trustXSendfileTypeHeader();
|
||||
}
|
||||
}
|
||||
|
||||
public function build(ContainerBuilder $container): void
|
||||
{
|
||||
parent::build($container);
|
||||
|
||||
$registerListenersPass = new RegisterListenersPass();
|
||||
$registerListenersPass->setHotPathEvents([
|
||||
KernelEvents::REQUEST,
|
||||
KernelEvents::CONTROLLER,
|
||||
KernelEvents::CONTROLLER_ARGUMENTS,
|
||||
KernelEvents::RESPONSE,
|
||||
KernelEvents::FINISH_REQUEST,
|
||||
]);
|
||||
if (class_exists(ConsoleEvents::class)) {
|
||||
$registerListenersPass->setNoPreloadEvents([
|
||||
ConsoleEvents::COMMAND,
|
||||
ConsoleEvents::TERMINATE,
|
||||
ConsoleEvents::ERROR,
|
||||
]);
|
||||
}
|
||||
|
||||
$container->addCompilerPass(new AssetsContextPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION);
|
||||
$container->addCompilerPass(new LoggerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
|
||||
$container->addCompilerPass(new RegisterControllerArgumentLocatorsPass());
|
||||
$container->addCompilerPass(new RemoveEmptyControllerArgumentLocatorsPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||
$container->addCompilerPass(new RoutingResolverPass());
|
||||
$this->addCompilerPassIfExists($container, DataCollectorTranslatorPass::class);
|
||||
$container->addCompilerPass(new ProfilerPass());
|
||||
// must be registered before removing private services as some might be listeners/subscribers
|
||||
// but as late as possible to get resolved parameters
|
||||
$container->addCompilerPass($registerListenersPass, PassConfig::TYPE_BEFORE_REMOVING);
|
||||
$this->addCompilerPassIfExists($container, AddConstraintValidatorsPass::class);
|
||||
$this->addCompilerPassIfExists($container, AddValidatorInitializersPass::class);
|
||||
$this->addCompilerPassIfExists($container, AddConsoleCommandPass::class, PassConfig::TYPE_BEFORE_REMOVING);
|
||||
// must be registered before the AddConsoleCommandPass
|
||||
$container->addCompilerPass(new TranslationLintCommandPass(), PassConfig::TYPE_BEFORE_REMOVING, 10);
|
||||
// must be registered as late as possible to get access to all Twig paths registered in
|
||||
// twig.template_iterator definition
|
||||
$this->addCompilerPassIfExists($container, TranslatorPass::class, PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
|
||||
$this->addCompilerPassIfExists($container, TranslatorPathsPass::class, PassConfig::TYPE_AFTER_REMOVING);
|
||||
$this->addCompilerPassIfExists($container, LoggingTranslatorPass::class);
|
||||
$container->addCompilerPass(new AddExpressionLanguageProvidersPass());
|
||||
$this->addCompilerPassIfExists($container, TranslationExtractorPass::class);
|
||||
$this->addCompilerPassIfExists($container, TranslationDumperPass::class);
|
||||
$container->addCompilerPass(new FragmentRendererPass());
|
||||
$this->addCompilerPassIfExists($container, SerializerPass::class);
|
||||
$this->addCompilerPassIfExists($container, PropertyInfoPass::class);
|
||||
$this->addCompilerPassIfExists($container, PropertyInfoConstructorPass::class);
|
||||
$container->addCompilerPass(new ControllerArgumentValueResolverPass());
|
||||
$container->addCompilerPass(new CachePoolPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 32);
|
||||
$container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING);
|
||||
$container->addCompilerPass(new CachePoolPrunerPass(), PassConfig::TYPE_AFTER_REMOVING);
|
||||
$this->addCompilerPassIfExists($container, FormPass::class);
|
||||
$this->addCompilerPassIfExists($container, WorkflowGuardListenerPass::class);
|
||||
$this->addCompilerPassIfExists($container, WorkflowValidatorPass::class);
|
||||
$container->addCompilerPass(new ResettableServicePass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
|
||||
$container->addCompilerPass(new RegisterLocaleAwareServicesPass());
|
||||
$container->addCompilerPass(new TestServiceContainerWeakRefPass(), PassConfig::TYPE_BEFORE_REMOVING, -32);
|
||||
$container->addCompilerPass(new TestServiceContainerRealRefPass(), PassConfig::TYPE_AFTER_REMOVING);
|
||||
$this->addCompilerPassIfExists($container, AddMimeTypeGuesserPass::class);
|
||||
$this->addCompilerPassIfExists($container, AddScheduleMessengerPass::class);
|
||||
$this->addCompilerPassIfExists($container, MessengerPass::class);
|
||||
$this->addCompilerPassIfExists($container, HttpClientPass::class);
|
||||
$this->addCompilerPassIfExists($container, AddAutoMappingConfigurationPass::class);
|
||||
$container->addCompilerPass(new RegisterReverseContainerPass(true));
|
||||
$container->addCompilerPass(new RegisterReverseContainerPass(false), PassConfig::TYPE_AFTER_REMOVING);
|
||||
$container->addCompilerPass(new RemoveUnusedSessionMarshallingHandlerPass());
|
||||
// must be registered after MonologBundle's LoggerChannelPass
|
||||
$container->addCompilerPass(new ErrorLoggerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32);
|
||||
$container->addCompilerPass(new VirtualRequestStackPass());
|
||||
$container->addCompilerPass(new TranslationUpdateCommandPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||
$this->addCompilerPassIfExists($container, StreamablePass::class);
|
||||
|
||||
if ($container->getParameter('kernel.debug')) {
|
||||
$container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 2);
|
||||
$container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING);
|
||||
$container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_BEFORE_REMOVING, -255);
|
||||
$container->addCompilerPass(new CacheCollectorPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||
$this->addCompilerPassIfExists($container, WorkflowDebugPass::class);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function considerProfilerEnabled(): bool
|
||||
{
|
||||
return !($GLOBALS['app'] ?? null) instanceof Application || empty($_GET) && \in_array('--profile', $_SERVER['argv'] ?? [], true);
|
||||
}
|
||||
|
||||
private function addCompilerPassIfExists(ContainerBuilder $container, string $class, string $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0): void
|
||||
{
|
||||
$container->addResource(new ClassExistenceResource($class));
|
||||
|
||||
if (class_exists($class)) {
|
||||
$container->addCompilerPass(new $class(), $type, $priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
88
vendor/symfony/framework-bundle/HttpCache/HttpCache.php
vendored
Normal file
88
vendor/symfony/framework-bundle/HttpCache/HttpCache.php
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
<?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\Bundle\FrameworkBundle\HttpCache;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\HttpCache\Esi;
|
||||
use Symfony\Component\HttpKernel\HttpCache\HttpCache as BaseHttpCache;
|
||||
use Symfony\Component\HttpKernel\HttpCache\Store;
|
||||
use Symfony\Component\HttpKernel\HttpCache\StoreInterface;
|
||||
use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
|
||||
/**
|
||||
* Manages HTTP cache objects in a Container.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class HttpCache extends BaseHttpCache
|
||||
{
|
||||
protected ?string $cacheDir = null;
|
||||
|
||||
private ?StoreInterface $store = null;
|
||||
private array $options;
|
||||
|
||||
/**
|
||||
* @param $cache The cache directory (default used if null) or the storage instance
|
||||
*/
|
||||
public function __construct(
|
||||
protected KernelInterface $kernel,
|
||||
string|StoreInterface|null $cache = null,
|
||||
private ?SurrogateInterface $surrogate = null,
|
||||
?array $options = null,
|
||||
) {
|
||||
$this->options = $options ?? [];
|
||||
|
||||
if ($cache instanceof StoreInterface) {
|
||||
$this->store = $cache;
|
||||
} else {
|
||||
$this->cacheDir = $cache;
|
||||
}
|
||||
|
||||
if (null === $options && $kernel->isDebug()) {
|
||||
$this->options = ['debug' => true];
|
||||
}
|
||||
|
||||
if ($this->options['debug'] ?? false) {
|
||||
$this->options += ['stale_if_error' => 0];
|
||||
}
|
||||
|
||||
parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge($this->options, $this->getOptions()));
|
||||
}
|
||||
|
||||
protected function forward(Request $request, bool $catch = false, ?Response $entry = null): Response
|
||||
{
|
||||
$this->getKernel()->boot();
|
||||
$this->getKernel()->getContainer()->set('cache', $this);
|
||||
|
||||
return parent::forward($request, $catch, $entry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of options to customize the Cache configuration.
|
||||
*/
|
||||
protected function getOptions(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function createSurrogate(): SurrogateInterface
|
||||
{
|
||||
return $this->surrogate ?? new Esi();
|
||||
}
|
||||
|
||||
protected function createStore(): StoreInterface
|
||||
{
|
||||
return $this->store ?? new Store($this->cacheDir ?: $this->kernel->getCacheDir().'/http_cache');
|
||||
}
|
||||
}
|
||||
233
vendor/symfony/framework-bundle/Kernel/MicroKernelTrait.php
vendored
Normal file
233
vendor/symfony/framework-bundle/Kernel/MicroKernelTrait.php
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
<?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\Bundle\FrameworkBundle\Kernel;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
use Symfony\Component\Config\Loader\LoaderInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\AbstractConfigurator;
|
||||
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
|
||||
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader as ContainerPhpFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\Routing\Loader\Configurator\RoutingConfigurator;
|
||||
use Symfony\Component\Routing\Loader\PhpFileLoader as RoutingPhpFileLoader;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
/**
|
||||
* A Kernel that provides configuration hooks.
|
||||
*
|
||||
* @author Ryan Weaver <ryan@knpuniversity.com>
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
trait MicroKernelTrait
|
||||
{
|
||||
/**
|
||||
* Configures the container.
|
||||
*
|
||||
* You can register extensions:
|
||||
*
|
||||
* $container->extension('framework', [
|
||||
* 'secret' => '%secret%'
|
||||
* ]);
|
||||
*
|
||||
* Or services:
|
||||
*
|
||||
* $container->services()->set('halloween', 'FooBundle\HalloweenProvider');
|
||||
*
|
||||
* Or parameters:
|
||||
*
|
||||
* $container->parameters()->set('halloween', 'lot of fun');
|
||||
*/
|
||||
private function configureContainer(ContainerConfigurator $container, LoaderInterface $loader, ContainerBuilder $builder): void
|
||||
{
|
||||
$configDir = preg_replace('{/config$}', '/{config}', $this->getConfigDir());
|
||||
|
||||
$container->import($configDir.'/{packages}/*.{php,yaml}');
|
||||
$container->import($configDir.'/{packages}/'.$this->environment.'/*.{php,yaml}');
|
||||
|
||||
if (is_file($this->getConfigDir().'/services.yaml')) {
|
||||
$container->import($configDir.'/services.yaml');
|
||||
$container->import($configDir.'/{services}_'.$this->environment.'.yaml');
|
||||
} else {
|
||||
$container->import($configDir.'/{services}.php');
|
||||
$container->import($configDir.'/{services}_'.$this->environment.'.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or imports routes into your application.
|
||||
*
|
||||
* $routes->import($this->getConfigDir().'/*.{yaml,php}');
|
||||
* $routes
|
||||
* ->add('admin_dashboard', '/admin')
|
||||
* ->controller('App\Controller\AdminController::dashboard')
|
||||
* ;
|
||||
*/
|
||||
private function configureRoutes(RoutingConfigurator $routes): void
|
||||
{
|
||||
$configDir = preg_replace('{/config$}', '/{config}', $this->getConfigDir());
|
||||
|
||||
$routes->import($configDir.'/{routes}/'.$this->environment.'/*.{php,yaml}');
|
||||
$routes->import($configDir.'/{routes}/*.{php,yaml}');
|
||||
|
||||
if (is_file($this->getConfigDir().'/routes.yaml')) {
|
||||
$routes->import($configDir.'/routes.yaml');
|
||||
} else {
|
||||
$routes->import($configDir.'/{routes}.php');
|
||||
}
|
||||
|
||||
if ($fileName = (new \ReflectionObject($this))->getFileName()) {
|
||||
$routes->import($fileName, 'attribute');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path to the configuration directory.
|
||||
*/
|
||||
private function getConfigDir(): string
|
||||
{
|
||||
return $this->getProjectDir().'/config';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path to the bundles configuration file.
|
||||
*/
|
||||
private function getBundlesPath(): string
|
||||
{
|
||||
return $this->getConfigDir().'/bundles.php';
|
||||
}
|
||||
|
||||
public function getCacheDir(): string
|
||||
{
|
||||
if (isset($_SERVER['APP_CACHE_DIR'])) {
|
||||
return $_SERVER['APP_CACHE_DIR'].'/'.$this->environment;
|
||||
}
|
||||
|
||||
return parent::getCacheDir();
|
||||
}
|
||||
|
||||
public function getBuildDir(): string
|
||||
{
|
||||
if (isset($_SERVER['APP_BUILD_DIR'])) {
|
||||
return $_SERVER['APP_BUILD_DIR'].'/'.$this->environment;
|
||||
}
|
||||
|
||||
return parent::getBuildDir();
|
||||
}
|
||||
|
||||
public function getLogDir(): string
|
||||
{
|
||||
return $_SERVER['APP_LOG_DIR'] ?? parent::getLogDir();
|
||||
}
|
||||
|
||||
public function registerBundles(): iterable
|
||||
{
|
||||
if (!is_file($bundlesPath = $this->getBundlesPath())) {
|
||||
yield new FrameworkBundle();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$contents = require $bundlesPath;
|
||||
foreach ($contents as $class => $envs) {
|
||||
if ($envs[$this->environment] ?? $envs['all'] ?? false) {
|
||||
yield new $class();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function registerContainerConfiguration(LoaderInterface $loader): void
|
||||
{
|
||||
$loader->load(function (ContainerBuilder $container) use ($loader) {
|
||||
$container->loadFromExtension('framework', [
|
||||
'router' => [
|
||||
'resource' => 'kernel::loadRoutes',
|
||||
'type' => 'service',
|
||||
],
|
||||
]);
|
||||
|
||||
$kernelClass = str_contains(static::class, "@anonymous\0") ? parent::class : static::class;
|
||||
|
||||
if (!$container->hasDefinition('kernel')) {
|
||||
$container->register('kernel', $kernelClass)
|
||||
->addTag('controller.service_arguments')
|
||||
->setAutoconfigured(true)
|
||||
->setSynthetic(true)
|
||||
->setPublic(true)
|
||||
;
|
||||
}
|
||||
|
||||
$kernelDefinition = $container->getDefinition('kernel');
|
||||
$kernelDefinition->addTag('routing.route_loader');
|
||||
|
||||
$container->addObjectResource($this);
|
||||
$container->fileExists($this->getBundlesPath());
|
||||
|
||||
$configureContainer = new \ReflectionMethod($this, 'configureContainer');
|
||||
$configuratorClass = $configureContainer->getNumberOfParameters() > 0 && ($type = $configureContainer->getParameters()[0]->getType()) instanceof \ReflectionNamedType && !$type->isBuiltin() ? $type->getName() : null;
|
||||
|
||||
if ($configuratorClass && !is_a(ContainerConfigurator::class, $configuratorClass, true)) {
|
||||
$configureContainer->getClosure($this)($container, $loader);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$file = (new \ReflectionObject($this))->getFileName();
|
||||
/** @var ContainerPhpFileLoader $kernelLoader */
|
||||
$kernelLoader = $loader->getResolver()->resolve($file);
|
||||
$kernelLoader->setCurrentDir(\dirname($file));
|
||||
$instanceof = &\Closure::bind(fn &() => $this->instanceof, $kernelLoader, $kernelLoader)();
|
||||
|
||||
$valuePreProcessor = AbstractConfigurator::$valuePreProcessor;
|
||||
AbstractConfigurator::$valuePreProcessor = fn ($value) => $this === $value ? new Reference('kernel') : $value;
|
||||
|
||||
try {
|
||||
$configureContainer->getClosure($this)(new ContainerConfigurator($container, $kernelLoader, $instanceof, $file, $file, $this->getEnvironment()), $loader, $container);
|
||||
} finally {
|
||||
$instanceof = [];
|
||||
$kernelLoader->registerAliasesForSinglyImplementedInterfaces();
|
||||
AbstractConfigurator::$valuePreProcessor = $valuePreProcessor;
|
||||
}
|
||||
|
||||
$container->setAlias($kernelClass, 'kernel')->setPublic(true);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function loadRoutes(LoaderInterface $loader): RouteCollection
|
||||
{
|
||||
$file = (new \ReflectionObject($this))->getFileName();
|
||||
/** @var RoutingPhpFileLoader $kernelLoader */
|
||||
$kernelLoader = $loader->getResolver()->resolve($file, 'php');
|
||||
$kernelLoader->setCurrentDir(\dirname($file));
|
||||
$collection = new RouteCollection();
|
||||
|
||||
$configureRoutes = new \ReflectionMethod($this, 'configureRoutes');
|
||||
$configureRoutes->getClosure($this)(new RoutingConfigurator($collection, $kernelLoader, $file, $file, $this->getEnvironment()));
|
||||
|
||||
foreach ($collection as $route) {
|
||||
$controller = $route->getDefault('_controller');
|
||||
|
||||
if (\is_array($controller) && [0, 1] === array_keys($controller) && $this === $controller[0]) {
|
||||
$route->setDefault('_controller', ['kernel', $controller[1]]);
|
||||
} elseif ($controller instanceof \Closure && $this === ($r = new \ReflectionFunction($controller))->getClosureThis() && !$r->isAnonymous()) {
|
||||
$route->setDefault('_controller', ['kernel', $r->name]);
|
||||
} elseif ($this::class === $controller && method_exists($this, '__invoke')) {
|
||||
$route->setDefault('_controller', 'kernel');
|
||||
}
|
||||
}
|
||||
|
||||
return $collection;
|
||||
}
|
||||
}
|
||||
230
vendor/symfony/framework-bundle/KernelBrowser.php
vendored
Normal file
230
vendor/symfony/framework-bundle/KernelBrowser.php
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
<?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\Bundle\FrameworkBundle;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Test\TestBrowserToken;
|
||||
use Symfony\Component\BrowserKit\Cookie;
|
||||
use Symfony\Component\BrowserKit\CookieJar;
|
||||
use Symfony\Component\BrowserKit\History;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\HttpKernelBrowser;
|
||||
use Symfony\Component\HttpKernel\KernelInterface;
|
||||
use Symfony\Component\HttpKernel\Profiler\Profile as HttpProfile;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* Simulates a browser and makes requests to a Kernel object.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class KernelBrowser extends HttpKernelBrowser
|
||||
{
|
||||
private bool $hasPerformedRequest = false;
|
||||
private bool $profiler = false;
|
||||
private bool $reboot = true;
|
||||
|
||||
public function __construct(KernelInterface $kernel, array $server = [], ?History $history = null, ?CookieJar $cookieJar = null)
|
||||
{
|
||||
parent::__construct($kernel, $server, $history, $cookieJar);
|
||||
}
|
||||
|
||||
public function getContainer(): ContainerInterface
|
||||
{
|
||||
$container = $this->kernel->getContainer();
|
||||
|
||||
return $container->has('test.service_container') ? $container->get('test.service_container') : $container;
|
||||
}
|
||||
|
||||
public function getKernel(): KernelInterface
|
||||
{
|
||||
return $this->kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the profile associated with the current Response.
|
||||
*/
|
||||
public function getProfile(): HttpProfile|false|null
|
||||
{
|
||||
if (!isset($this->response) || !$this->getContainer()->has('profiler')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->getContainer()->get('profiler')->loadProfileFromResponse($this->response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the profiler for the very next request.
|
||||
*
|
||||
* If the profiler is not enabled, the call to this method does nothing.
|
||||
*/
|
||||
public function enableProfiler(): void
|
||||
{
|
||||
if ($this->getContainer()->has('profiler')) {
|
||||
$this->profiler = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables kernel reboot between requests.
|
||||
*
|
||||
* By default, the Client reboots the Kernel for each request. This method
|
||||
* allows to keep the same kernel across requests.
|
||||
*/
|
||||
public function disableReboot(): void
|
||||
{
|
||||
$this->reboot = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables kernel reboot between requests.
|
||||
*/
|
||||
public function enableReboot(): void
|
||||
{
|
||||
$this->reboot = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UserInterface $user
|
||||
* @param array<string, mixed> $tokenAttributes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function loginUser(object $user, string $firewallContext = 'main', array $tokenAttributes = []): static
|
||||
{
|
||||
if (!interface_exists(UserInterface::class)) {
|
||||
throw new \LogicException(\sprintf('"%s" requires symfony/security-core to be installed. Try running "composer require symfony/security-core".', __METHOD__));
|
||||
}
|
||||
|
||||
if (!$user instanceof UserInterface) {
|
||||
throw new \LogicException(\sprintf('The first argument of "%s" must be instance of "%s", "%s" provided.', __METHOD__, UserInterface::class, get_debug_type($user)));
|
||||
}
|
||||
|
||||
$token = new TestBrowserToken($user->getRoles(), $user, $firewallContext);
|
||||
$token->setAttributes($tokenAttributes);
|
||||
|
||||
$container = $this->getContainer();
|
||||
$container->get('security.untracked_token_storage')->setToken($token);
|
||||
|
||||
if (!$container->has('session.factory')) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$session = $container->get('session.factory')->createSession();
|
||||
$session->set('_security_'.$firewallContext, serialize($token));
|
||||
$session->save();
|
||||
|
||||
$domains = array_unique(array_map(fn (Cookie $cookie) => $cookie->getName() === $session->getName() ? $cookie->getDomain() : '', $this->getCookieJar()->all())) ?: [''];
|
||||
foreach ($domains as $domain) {
|
||||
$cookie = new Cookie($session->getName(), $session->getId(), null, null, $domain);
|
||||
$this->getCookieJar()->set($cookie);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*/
|
||||
protected function doRequest(object $request): Response
|
||||
{
|
||||
// avoid shutting down the Kernel if no request has been performed yet
|
||||
// WebTestCase::createClient() boots the Kernel but do not handle a request
|
||||
if ($this->hasPerformedRequest && $this->reboot) {
|
||||
$this->kernel->boot();
|
||||
$this->kernel->shutdown();
|
||||
} else {
|
||||
$this->hasPerformedRequest = true;
|
||||
}
|
||||
|
||||
if ($this->profiler) {
|
||||
$this->profiler = false;
|
||||
|
||||
$this->kernel->boot();
|
||||
$this->getContainer()->get('profiler')->enable();
|
||||
}
|
||||
|
||||
return parent::doRequest($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
*/
|
||||
protected function doRequestInProcess(object $request): Response
|
||||
{
|
||||
$response = parent::doRequestInProcess($request);
|
||||
|
||||
$this->profiler = false;
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the script to execute when the request must be insulated.
|
||||
*
|
||||
* It assumes that the autoloader is named 'autoload.php' and that it is
|
||||
* stored in the same directory as the kernel (this is the case for the
|
||||
* Symfony Standard Edition). If this is not your case, create your own
|
||||
* client and override this method.
|
||||
*
|
||||
* @param Request $request
|
||||
*/
|
||||
protected function getScript(object $request): string
|
||||
{
|
||||
$kernel = var_export(serialize($this->kernel), true);
|
||||
$request = var_export(serialize($request), true);
|
||||
$errorReporting = error_reporting();
|
||||
|
||||
$requires = '';
|
||||
foreach (get_declared_classes() as $class) {
|
||||
if (str_starts_with($class, 'ComposerAutoloaderInit')) {
|
||||
$r = new \ReflectionClass($class);
|
||||
$file = \dirname($r->getFileName(), 2).'/autoload.php';
|
||||
if (is_file($file)) {
|
||||
$requires .= 'require_once '.var_export($file, true).";\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$requires) {
|
||||
throw new \RuntimeException('Composer autoloader not found.');
|
||||
}
|
||||
|
||||
$requires .= 'require_once '.var_export((new \ReflectionObject($this->kernel))->getFileName(), true).";\n";
|
||||
|
||||
$profilerCode = '';
|
||||
if ($this->profiler) {
|
||||
$profilerCode = <<<'EOF'
|
||||
$container = $kernel->getContainer();
|
||||
$container = $container->has('test.service_container') ? $container->get('test.service_container') : $container;
|
||||
$container->get('profiler')->enable();
|
||||
EOF;
|
||||
}
|
||||
|
||||
$code = <<<EOF
|
||||
<?php
|
||||
|
||||
error_reporting($errorReporting);
|
||||
|
||||
$requires
|
||||
|
||||
\$kernel = unserialize($kernel);
|
||||
\$kernel->boot();
|
||||
$profilerCode
|
||||
|
||||
\$request = unserialize($request);
|
||||
EOF;
|
||||
|
||||
return $code.$this->getHandleScript();
|
||||
}
|
||||
}
|
||||
19
vendor/symfony/framework-bundle/LICENSE
vendored
Normal file
19
vendor/symfony/framework-bundle/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2004-present Fabien Potencier
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
20
vendor/symfony/framework-bundle/README.md
vendored
Normal file
20
vendor/symfony/framework-bundle/README.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
FrameworkBundle
|
||||
===============
|
||||
|
||||
FrameworkBundle provides a tight integration between Symfony components and the
|
||||
Symfony full-stack framework.
|
||||
|
||||
Sponsor
|
||||
-------
|
||||
|
||||
Help Symfony by [sponsoring][1] its development!
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
|
||||
* [Report issues](https://github.com/symfony/symfony/issues) and
|
||||
[send Pull Requests](https://github.com/symfony/symfony/pulls)
|
||||
in the [main Symfony repository](https://github.com/symfony/symfony)
|
||||
|
||||
[1]: https://symfony.com/sponsor
|
||||
23
vendor/symfony/framework-bundle/Resources/bin/check-unused-known-tags.php
vendored
Normal file
23
vendor/symfony/framework-bundle/Resources/bin/check-unused-known-tags.php
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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.
|
||||
*/
|
||||
|
||||
if ('cli' !== \PHP_SAPI) {
|
||||
throw new Exception('This script must be run from the command line.');
|
||||
}
|
||||
|
||||
require dirname(__DIR__, 6).'/vendor/autoload.php';
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler\UnusedTagsPassUtils;
|
||||
|
||||
$target = dirname(__DIR__, 2).'/DependencyInjection/Compiler/UnusedTagsPass.php';
|
||||
$contents = file_get_contents($target);
|
||||
$contents = preg_replace('{private const KNOWN_TAGS = \[(.+?)\];}sm', "private const KNOWN_TAGS = [\n '".implode("',\n '", UnusedTagsPassUtils::getDefinedTags())."',\n ];", $contents);
|
||||
file_put_contents($target, $contents);
|
||||
280
vendor/symfony/framework-bundle/Resources/config/asset_mapper.php
vendored
Normal file
280
vendor/symfony/framework-bundle/Resources/config/asset_mapper.php
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\AssetMapper\AssetMapper;
|
||||
use Symfony\Component\AssetMapper\AssetMapperCompiler;
|
||||
use Symfony\Component\AssetMapper\AssetMapperDevServerSubscriber;
|
||||
use Symfony\Component\AssetMapper\AssetMapperInterface;
|
||||
use Symfony\Component\AssetMapper\AssetMapperRepository;
|
||||
use Symfony\Component\AssetMapper\Command\AssetMapperCompileCommand;
|
||||
use Symfony\Component\AssetMapper\Command\CompressAssetsCommand;
|
||||
use Symfony\Component\AssetMapper\Command\DebugAssetMapperCommand;
|
||||
use Symfony\Component\AssetMapper\Command\ImportMapAuditCommand;
|
||||
use Symfony\Component\AssetMapper\Command\ImportMapInstallCommand;
|
||||
use Symfony\Component\AssetMapper\Command\ImportMapOutdatedCommand;
|
||||
use Symfony\Component\AssetMapper\Command\ImportMapRemoveCommand;
|
||||
use Symfony\Component\AssetMapper\Command\ImportMapRequireCommand;
|
||||
use Symfony\Component\AssetMapper\Command\ImportMapUpdateCommand;
|
||||
use Symfony\Component\AssetMapper\CompiledAssetMapperConfigReader;
|
||||
use Symfony\Component\AssetMapper\Compiler\CssAssetUrlCompiler;
|
||||
use Symfony\Component\AssetMapper\Compiler\JavaScriptImportPathCompiler;
|
||||
use Symfony\Component\AssetMapper\Compiler\SourceMappingUrlsCompiler;
|
||||
use Symfony\Component\AssetMapper\Compressor\BrotliCompressor;
|
||||
use Symfony\Component\AssetMapper\Compressor\ChainCompressor;
|
||||
use Symfony\Component\AssetMapper\Compressor\CompressorInterface;
|
||||
use Symfony\Component\AssetMapper\Compressor\GzipCompressor;
|
||||
use Symfony\Component\AssetMapper\Compressor\ZstandardCompressor;
|
||||
use Symfony\Component\AssetMapper\Factory\CachedMappedAssetFactory;
|
||||
use Symfony\Component\AssetMapper\Factory\MappedAssetFactory;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapAuditor;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapConfigReader;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapGenerator;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapManager;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapRenderer;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapUpdateChecker;
|
||||
use Symfony\Component\AssetMapper\ImportMap\ImportMapVersionChecker;
|
||||
use Symfony\Component\AssetMapper\ImportMap\RemotePackageDownloader;
|
||||
use Symfony\Component\AssetMapper\ImportMap\RemotePackageStorage;
|
||||
use Symfony\Component\AssetMapper\ImportMap\Resolver\JsDelivrEsmResolver;
|
||||
use Symfony\Component\AssetMapper\MapperAwareAssetPackage;
|
||||
use Symfony\Component\AssetMapper\Path\LocalPublicAssetsFilesystem;
|
||||
use Symfony\Component\AssetMapper\Path\PublicAssetsPathResolver;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('asset_mapper', AssetMapper::class)
|
||||
->args([
|
||||
service('asset_mapper.repository'),
|
||||
service('asset_mapper.mapped_asset_factory'),
|
||||
service('asset_mapper.compiled_asset_mapper_config_reader'),
|
||||
])
|
||||
->alias(AssetMapperInterface::class, 'asset_mapper')
|
||||
|
||||
->alias('asset_mapper.http_client', 'http_client')
|
||||
|
||||
->set('asset_mapper.mapped_asset_factory', MappedAssetFactory::class)
|
||||
->args([
|
||||
service('asset_mapper.public_assets_path_resolver'),
|
||||
service('asset_mapper_compiler'),
|
||||
abstract_arg('vendor directory'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.cached_mapped_asset_factory', CachedMappedAssetFactory::class)
|
||||
->args([
|
||||
service('.inner'),
|
||||
param('kernel.cache_dir').'/asset_mapper',
|
||||
param('kernel.debug'),
|
||||
])
|
||||
->decorate('asset_mapper.mapped_asset_factory')
|
||||
|
||||
->set('asset_mapper.repository', AssetMapperRepository::class)
|
||||
->args([
|
||||
abstract_arg('array of asset mapper paths'),
|
||||
param('kernel.project_dir'),
|
||||
abstract_arg('array of excluded path patterns'),
|
||||
abstract_arg('exclude dot files'),
|
||||
param('kernel.debug'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.public_assets_path_resolver', PublicAssetsPathResolver::class)
|
||||
->args([
|
||||
abstract_arg('asset public prefix'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.local_public_assets_filesystem', LocalPublicAssetsFilesystem::class)
|
||||
->args([
|
||||
abstract_arg('public directory'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.compiled_asset_mapper_config_reader', CompiledAssetMapperConfigReader::class)
|
||||
->args([
|
||||
abstract_arg('public assets directory'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.asset_package', MapperAwareAssetPackage::class)
|
||||
->decorate('assets._default_package')
|
||||
->args([
|
||||
service('.inner'),
|
||||
service('asset_mapper'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.dev_server_subscriber', AssetMapperDevServerSubscriber::class)
|
||||
->args([
|
||||
service('asset_mapper'),
|
||||
abstract_arg('asset public prefix'),
|
||||
abstract_arg('extensions map'),
|
||||
service('cache.asset_mapper'),
|
||||
service('profiler')->nullOnInvalid(),
|
||||
])
|
||||
->tag('kernel.event_subscriber')
|
||||
|
||||
->set('asset_mapper.command.compile', AssetMapperCompileCommand::class)
|
||||
->args([
|
||||
service('asset_mapper.compiled_asset_mapper_config_reader'),
|
||||
service('asset_mapper'),
|
||||
service('asset_mapper.importmap.generator'),
|
||||
service('asset_mapper.local_public_assets_filesystem'),
|
||||
param('kernel.project_dir'),
|
||||
param('kernel.debug'),
|
||||
service('event_dispatcher')->nullOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('asset_mapper.command.debug', DebugAssetMapperCommand::class)
|
||||
->args([
|
||||
service('asset_mapper'),
|
||||
service('asset_mapper.repository'),
|
||||
param('kernel.project_dir'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('asset_mapper_compiler', AssetMapperCompiler::class)
|
||||
->args([
|
||||
tagged_iterator('asset_mapper.compiler'),
|
||||
service_closure('asset_mapper'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.compiler.css_asset_url_compiler', CssAssetUrlCompiler::class)
|
||||
->args([
|
||||
abstract_arg('missing import mode'),
|
||||
service('logger'),
|
||||
])
|
||||
->tag('asset_mapper.compiler')
|
||||
->tag('monolog.logger', ['channel' => 'asset_mapper'])
|
||||
|
||||
->set('asset_mapper.compiler.source_mapping_urls_compiler', SourceMappingUrlsCompiler::class)
|
||||
->tag('asset_mapper.compiler')
|
||||
|
||||
->set('asset_mapper.compiler.javascript_import_path_compiler', JavaScriptImportPathCompiler::class)
|
||||
->args([
|
||||
service('asset_mapper.importmap.config_reader'),
|
||||
abstract_arg('missing import mode'),
|
||||
service('logger'),
|
||||
])
|
||||
->tag('asset_mapper.compiler')
|
||||
->tag('monolog.logger', ['channel' => 'asset_mapper'])
|
||||
|
||||
->set('asset_mapper.importmap.config_reader', ImportMapConfigReader::class)
|
||||
->args([
|
||||
abstract_arg('importmap.php path'),
|
||||
service('asset_mapper.importmap.remote_package_storage'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.importmap.manager', ImportMapManager::class)
|
||||
->args([
|
||||
service('asset_mapper'),
|
||||
service('asset_mapper.importmap.config_reader'),
|
||||
service('asset_mapper.importmap.remote_package_downloader'),
|
||||
service('asset_mapper.importmap.resolver'),
|
||||
])
|
||||
->alias(ImportMapManager::class, 'asset_mapper.importmap.manager')
|
||||
|
||||
->set('asset_mapper.importmap.generator', ImportMapGenerator::class)
|
||||
->args([
|
||||
service('asset_mapper'),
|
||||
service('asset_mapper.compiled_asset_mapper_config_reader'),
|
||||
service('asset_mapper.importmap.config_reader'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.importmap.remote_package_storage', RemotePackageStorage::class)
|
||||
->args([
|
||||
abstract_arg('vendor directory'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.importmap.remote_package_downloader', RemotePackageDownloader::class)
|
||||
->args([
|
||||
service('asset_mapper.importmap.remote_package_storage'),
|
||||
service('asset_mapper.importmap.config_reader'),
|
||||
service('asset_mapper.importmap.resolver'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.importmap.version_checker', ImportMapVersionChecker::class)
|
||||
->args([
|
||||
service('asset_mapper.importmap.config_reader'),
|
||||
service('asset_mapper.importmap.remote_package_downloader'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.importmap.resolver', JsDelivrEsmResolver::class)
|
||||
->args([service('asset_mapper.http_client')])
|
||||
|
||||
->set('asset_mapper.importmap.renderer', ImportMapRenderer::class)
|
||||
->args([
|
||||
service('asset_mapper.importmap.generator'),
|
||||
service('assets.packages')->nullOnInvalid(),
|
||||
param('kernel.charset'),
|
||||
abstract_arg('polyfill URL'),
|
||||
abstract_arg('script HTML attributes'),
|
||||
service('request_stack'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.importmap.auditor', ImportMapAuditor::class)
|
||||
->args([
|
||||
service('asset_mapper.importmap.config_reader'),
|
||||
service('asset_mapper.http_client'),
|
||||
])
|
||||
->set('asset_mapper.importmap.update_checker', ImportMapUpdateChecker::class)
|
||||
->args([
|
||||
service('asset_mapper.importmap.config_reader'),
|
||||
service('asset_mapper.http_client'),
|
||||
])
|
||||
|
||||
->set('asset_mapper.importmap.command.require', ImportMapRequireCommand::class)
|
||||
->args([
|
||||
service('asset_mapper.importmap.manager'),
|
||||
service('asset_mapper.importmap.version_checker'),
|
||||
param('kernel.project_dir'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('asset_mapper.importmap.command.remove', ImportMapRemoveCommand::class)
|
||||
->args([service('asset_mapper.importmap.manager')])
|
||||
->tag('console.command')
|
||||
|
||||
->set('asset_mapper.importmap.command.update', ImportMapUpdateCommand::class)
|
||||
->args([
|
||||
service('asset_mapper.importmap.manager'),
|
||||
service('asset_mapper.importmap.version_checker'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('asset_mapper.importmap.command.install', ImportMapInstallCommand::class)
|
||||
->args([
|
||||
service('asset_mapper.importmap.remote_package_downloader'),
|
||||
param('kernel.project_dir'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('asset_mapper.importmap.command.audit', ImportMapAuditCommand::class)
|
||||
->args([service('asset_mapper.importmap.auditor')])
|
||||
->tag('console.command')
|
||||
|
||||
->set('asset_mapper.importmap.command.outdated', ImportMapOutdatedCommand::class)
|
||||
->args([service('asset_mapper.importmap.update_checker')])
|
||||
->tag('console.command')
|
||||
|
||||
->set('asset_mapper.compressor.brotli', BrotliCompressor::class)
|
||||
->set('asset_mapper.compressor.zstandard', ZstandardCompressor::class)
|
||||
->set('asset_mapper.compressor.gzip', GzipCompressor::class)
|
||||
|
||||
->set('asset_mapper.compressor', ChainCompressor::class)
|
||||
->args([
|
||||
abstract_arg('compressor'),
|
||||
service('logger'),
|
||||
])
|
||||
->alias(CompressorInterface::class, 'asset_mapper.compressor')
|
||||
|
||||
->set('asset_mapper.assets.command.compress', CompressAssetsCommand::class)
|
||||
->args([service('asset_mapper.compressor')])
|
||||
->tag('console.command')
|
||||
;
|
||||
};
|
||||
85
vendor/symfony/framework-bundle/Resources/config/assets.php
vendored
Normal file
85
vendor/symfony/framework-bundle/Resources/config/assets.php
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\Asset\Context\RequestStackContext;
|
||||
use Symfony\Component\Asset\Package;
|
||||
use Symfony\Component\Asset\Packages;
|
||||
use Symfony\Component\Asset\PathPackage;
|
||||
use Symfony\Component\Asset\UrlPackage;
|
||||
use Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy;
|
||||
use Symfony\Component\Asset\VersionStrategy\JsonManifestVersionStrategy;
|
||||
use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->parameters()
|
||||
->set('asset.request_context.base_path', null)
|
||||
->set('asset.request_context.secure', null)
|
||||
;
|
||||
|
||||
$container->services()
|
||||
->set('assets.packages', Packages::class)
|
||||
->args([
|
||||
service('assets._default_package'),
|
||||
tagged_iterator('assets.package', 'package'),
|
||||
])
|
||||
|
||||
->alias(Packages::class, 'assets.packages')
|
||||
|
||||
->set('assets.empty_package', Package::class)
|
||||
->args([
|
||||
service('assets.empty_version_strategy'),
|
||||
])
|
||||
|
||||
->alias('assets._default_package', 'assets.empty_package')
|
||||
|
||||
->set('assets.context', RequestStackContext::class)
|
||||
->args([
|
||||
service('request_stack'),
|
||||
param('asset.request_context.base_path'),
|
||||
param('asset.request_context.secure'),
|
||||
])
|
||||
|
||||
->set('assets.path_package', PathPackage::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('base path'),
|
||||
abstract_arg('version strategy'),
|
||||
service('assets.context'),
|
||||
])
|
||||
|
||||
->set('assets.url_package', UrlPackage::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('base URLs'),
|
||||
abstract_arg('version strategy'),
|
||||
service('assets.context'),
|
||||
])
|
||||
|
||||
->set('assets.static_version_strategy', StaticVersionStrategy::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('version'),
|
||||
abstract_arg('format'),
|
||||
])
|
||||
|
||||
->set('assets.empty_version_strategy', EmptyVersionStrategy::class)
|
||||
|
||||
->set('assets.json_manifest_version_strategy', JsonManifestVersionStrategy::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('manifest path'),
|
||||
service('http_client')->nullOnInvalid(),
|
||||
false,
|
||||
])
|
||||
;
|
||||
};
|
||||
258
vendor/symfony/framework-bundle/Resources/config/cache.php
vendored
Normal file
258
vendor/symfony/framework-bundle/Resources/config/cache.php
vendored
Normal file
@@ -0,0 +1,258 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Psr\Cache\CacheItemPoolInterface;
|
||||
use Symfony\Component\Cache\Adapter\AbstractAdapter;
|
||||
use Symfony\Component\Cache\Adapter\AdapterInterface;
|
||||
use Symfony\Component\Cache\Adapter\ApcuAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ArrayAdapter;
|
||||
use Symfony\Component\Cache\Adapter\DoctrineDbalAdapter;
|
||||
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
|
||||
use Symfony\Component\Cache\Adapter\MemcachedAdapter;
|
||||
use Symfony\Component\Cache\Adapter\PdoAdapter;
|
||||
use Symfony\Component\Cache\Adapter\ProxyAdapter;
|
||||
use Symfony\Component\Cache\Adapter\RedisAdapter;
|
||||
use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter;
|
||||
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
|
||||
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
|
||||
use Symfony\Component\Cache\Messenger\EarlyExpirationHandler;
|
||||
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
|
||||
use Symfony\Contracts\Cache\CacheInterface;
|
||||
use Symfony\Contracts\Cache\NamespacedPoolInterface;
|
||||
use Symfony\Contracts\Cache\TagAwareCacheInterface;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('cache.app')
|
||||
->parent('cache.adapter.filesystem')
|
||||
->public()
|
||||
->tag('cache.pool', ['clearer' => 'cache.app_clearer'])
|
||||
|
||||
->set('cache.app.taggable', TagAwareAdapter::class)
|
||||
->args([service('cache.app')])
|
||||
->tag('cache.taggable', ['pool' => 'cache.app'])
|
||||
|
||||
->set('cache.system')
|
||||
->parent('cache.adapter.system')
|
||||
->public()
|
||||
->tag('cache.pool')
|
||||
|
||||
->set('cache.validator')
|
||||
->parent('cache.system')
|
||||
->private()
|
||||
->tag('cache.pool')
|
||||
|
||||
->set('cache.serializer')
|
||||
->parent('cache.system')
|
||||
->private()
|
||||
->tag('cache.pool')
|
||||
|
||||
->set('cache.property_info')
|
||||
->parent('cache.system')
|
||||
->private()
|
||||
->tag('cache.pool')
|
||||
|
||||
->set('cache.asset_mapper')
|
||||
->parent('cache.system')
|
||||
->private()
|
||||
->tag('cache.pool')
|
||||
|
||||
->set('cache.messenger.restart_workers_signal')
|
||||
->parent('cache.app')
|
||||
->private()
|
||||
->tag('cache.pool')
|
||||
|
||||
->set('cache.scheduler')
|
||||
->parent('cache.app')
|
||||
->private()
|
||||
->tag('cache.pool')
|
||||
|
||||
->set('cache.adapter.system', AdapterInterface::class)
|
||||
->abstract()
|
||||
->factory([AbstractAdapter::class, 'createSystemCache'])
|
||||
->args([
|
||||
'', // namespace
|
||||
0, // default lifetime
|
||||
abstract_arg('version'),
|
||||
\sprintf('%s/pools/system', param('kernel.cache_dir')),
|
||||
service('logger')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('cache.pool', ['clearer' => 'cache.system_clearer', 'reset' => 'reset'])
|
||||
->tag('monolog.logger', ['channel' => 'cache'])
|
||||
|
||||
->set('cache.adapter.apcu', ApcuAdapter::class)
|
||||
->abstract()
|
||||
->args([
|
||||
'', // namespace
|
||||
0, // default lifetime
|
||||
abstract_arg('version'),
|
||||
])
|
||||
->call('setLogger', [service('logger')->ignoreOnInvalid()])
|
||||
->tag('cache.pool', ['clearer' => 'cache.default_clearer', 'reset' => 'reset'])
|
||||
->tag('monolog.logger', ['channel' => 'cache'])
|
||||
|
||||
->set('cache.adapter.filesystem', FilesystemAdapter::class)
|
||||
->abstract()
|
||||
->args([
|
||||
'', // namespace
|
||||
0, // default lifetime
|
||||
\sprintf('%s/pools/app', param('kernel.cache_dir')),
|
||||
service('cache.default_marshaller')->ignoreOnInvalid(),
|
||||
])
|
||||
->call('setLogger', [service('logger')->ignoreOnInvalid()])
|
||||
->tag('cache.pool', ['clearer' => 'cache.default_clearer', 'reset' => 'reset'])
|
||||
->tag('monolog.logger', ['channel' => 'cache'])
|
||||
|
||||
->set('cache.adapter.psr6', ProxyAdapter::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('PSR-6 provider service'),
|
||||
'', // namespace
|
||||
0, // default lifetime
|
||||
])
|
||||
->tag('cache.pool', [
|
||||
'provider' => 'cache.default_psr6_provider',
|
||||
'clearer' => 'cache.default_clearer',
|
||||
'reset' => 'reset',
|
||||
])
|
||||
|
||||
->set('cache.adapter.redis', RedisAdapter::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('Redis connection service'),
|
||||
'', // namespace
|
||||
0, // default lifetime
|
||||
service('cache.default_marshaller')->ignoreOnInvalid(),
|
||||
])
|
||||
->call('setLogger', [service('logger')->ignoreOnInvalid()])
|
||||
->tag('cache.pool', [
|
||||
'provider' => 'cache.default_redis_provider',
|
||||
'clearer' => 'cache.default_clearer',
|
||||
'reset' => 'reset',
|
||||
])
|
||||
->tag('monolog.logger', ['channel' => 'cache'])
|
||||
->alias('cache.adapter.valkey', 'cache.adapter.redis')
|
||||
|
||||
->set('cache.adapter.redis_tag_aware', RedisTagAwareAdapter::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('Redis connection service'),
|
||||
'', // namespace
|
||||
0, // default lifetime
|
||||
service('cache.default_marshaller')->ignoreOnInvalid(),
|
||||
])
|
||||
->call('setLogger', [service('logger')->ignoreOnInvalid()])
|
||||
->tag('cache.pool', [
|
||||
'provider' => 'cache.default_redis_provider',
|
||||
'clearer' => 'cache.default_clearer',
|
||||
'reset' => 'reset',
|
||||
])
|
||||
->tag('monolog.logger', ['channel' => 'cache'])
|
||||
->alias('cache.adapter.valkey_tag_aware', 'cache.adapter.redis_tag_aware')
|
||||
|
||||
->set('cache.adapter.memcached', MemcachedAdapter::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('Memcached connection service'),
|
||||
'', // namespace
|
||||
0, // default lifetime
|
||||
service('cache.default_marshaller')->ignoreOnInvalid(),
|
||||
])
|
||||
->call('setLogger', [service('logger')->ignoreOnInvalid()])
|
||||
->tag('cache.pool', [
|
||||
'provider' => 'cache.default_memcached_provider',
|
||||
'clearer' => 'cache.default_clearer',
|
||||
'reset' => 'reset',
|
||||
])
|
||||
->tag('monolog.logger', ['channel' => 'cache'])
|
||||
|
||||
->set('cache.adapter.doctrine_dbal', DoctrineDbalAdapter::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('DBAL connection service'),
|
||||
'', // namespace
|
||||
0, // default lifetime
|
||||
[], // table options
|
||||
service('cache.default_marshaller')->ignoreOnInvalid(),
|
||||
])
|
||||
->call('setLogger', [service('logger')->ignoreOnInvalid()])
|
||||
->tag('cache.pool', [
|
||||
'provider' => 'cache.default_doctrine_dbal_provider',
|
||||
'clearer' => 'cache.default_clearer',
|
||||
'reset' => 'reset',
|
||||
])
|
||||
->tag('monolog.logger', ['channel' => 'cache'])
|
||||
|
||||
->set('cache.adapter.pdo', PdoAdapter::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('PDO connection service'),
|
||||
'', // namespace
|
||||
0, // default lifetime
|
||||
[], // table options
|
||||
service('cache.default_marshaller')->ignoreOnInvalid(),
|
||||
])
|
||||
->call('setLogger', [service('logger')->ignoreOnInvalid()])
|
||||
->tag('cache.pool', [
|
||||
'provider' => 'cache.default_pdo_provider',
|
||||
'clearer' => 'cache.default_clearer',
|
||||
'reset' => 'reset',
|
||||
])
|
||||
->tag('monolog.logger', ['channel' => 'cache'])
|
||||
|
||||
->set('cache.adapter.array', ArrayAdapter::class)
|
||||
->abstract()
|
||||
->args([
|
||||
0, // default lifetime
|
||||
])
|
||||
->call('setLogger', [service('logger')->ignoreOnInvalid()])
|
||||
->tag('cache.pool', ['clearer' => 'cache.default_clearer', 'reset' => 'reset'])
|
||||
->tag('monolog.logger', ['channel' => 'cache'])
|
||||
|
||||
->set('cache.default_marshaller', DefaultMarshaller::class)
|
||||
->args([
|
||||
null, // use igbinary_serialize() when available
|
||||
'%kernel.debug%',
|
||||
])
|
||||
|
||||
->set('cache.early_expiration_handler', EarlyExpirationHandler::class)
|
||||
->args([
|
||||
service('reverse_container'),
|
||||
])
|
||||
->tag('messenger.message_handler')
|
||||
|
||||
->set('cache.default_clearer', Psr6CacheClearer::class)
|
||||
->args([
|
||||
[],
|
||||
])
|
||||
|
||||
->set('cache.system_clearer')
|
||||
->parent('cache.default_clearer')
|
||||
->public()
|
||||
|
||||
->set('cache.global_clearer')
|
||||
->parent('cache.default_clearer')
|
||||
->public()
|
||||
|
||||
->alias('cache.app_clearer', 'cache.default_clearer')
|
||||
->public()
|
||||
|
||||
->alias(CacheItemPoolInterface::class, 'cache.app')
|
||||
|
||||
->alias(CacheInterface::class, 'cache.app')
|
||||
|
||||
->alias(NamespacedPoolInterface::class, 'cache.app')
|
||||
|
||||
->alias(TagAwareCacheInterface::class, 'cache.app.taggable')
|
||||
;
|
||||
};
|
||||
39
vendor/symfony/framework-bundle/Resources/config/cache_debug.php
vendored
Normal file
39
vendor/symfony/framework-bundle/Resources/config/cache_debug.php
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\CacheWarmer\CachePoolClearerCacheWarmer;
|
||||
use Symfony\Component\Cache\DataCollector\CacheDataCollector;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
// DataCollector (public to prevent inlining, made private in CacheCollectorPass)
|
||||
->set('data_collector.cache', CacheDataCollector::class)
|
||||
->public()
|
||||
->tag('data_collector', [
|
||||
'template' => '@WebProfiler/Collector/cache.html.twig',
|
||||
'id' => 'cache',
|
||||
'priority' => 275,
|
||||
])
|
||||
|
||||
// CacheWarmer used in dev to clear cache pool
|
||||
->set('cache_pool_clearer.cache_warmer', CachePoolClearerCacheWarmer::class)
|
||||
->args([
|
||||
service('cache.system_clearer'),
|
||||
[
|
||||
'cache.validator',
|
||||
'cache.serializer',
|
||||
],
|
||||
])
|
||||
->tag('kernel.cache_warmer', ['priority' => 64])
|
||||
;
|
||||
};
|
||||
82
vendor/symfony/framework-bundle/Resources/config/collectors.php
vendored
Normal file
82
vendor/symfony/framework-bundle/Resources/config/collectors.php
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\DataCollector\RouterDataCollector;
|
||||
use Symfony\Component\Console\DataCollector\CommandDataCollector;
|
||||
use Symfony\Component\HttpKernel\DataCollector\AjaxDataCollector;
|
||||
use Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector;
|
||||
use Symfony\Component\HttpKernel\DataCollector\EventDataCollector;
|
||||
use Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector;
|
||||
use Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector;
|
||||
use Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector;
|
||||
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector;
|
||||
use Symfony\Component\HttpKernel\DataCollector\TimeDataCollector;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('data_collector.config', ConfigDataCollector::class)
|
||||
->call('setKernel', [service('kernel')->ignoreOnInvalid()])
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/config.html.twig', 'id' => 'config', 'priority' => -255])
|
||||
|
||||
->set('data_collector.request', RequestDataCollector::class)
|
||||
->args([
|
||||
service('.virtual_request_stack')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('kernel.event_subscriber')
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/request.html.twig', 'id' => 'request', 'priority' => 335])
|
||||
|
||||
->set('data_collector.request.session_collector', \Closure::class)
|
||||
->factory([\Closure::class, 'fromCallable'])
|
||||
->args([[service('data_collector.request'), 'collectSessionUsage']])
|
||||
|
||||
->set('data_collector.ajax', AjaxDataCollector::class)
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/ajax.html.twig', 'id' => 'ajax', 'priority' => 315])
|
||||
|
||||
->set('data_collector.exception', ExceptionDataCollector::class)
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/exception.html.twig', 'id' => 'exception', 'priority' => 305])
|
||||
|
||||
->set('data_collector.events', EventDataCollector::class)
|
||||
->args([
|
||||
tagged_iterator('event_dispatcher.dispatcher', 'name'),
|
||||
service('.virtual_request_stack')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/events.html.twig', 'id' => 'events', 'priority' => 290])
|
||||
|
||||
->set('data_collector.logger', LoggerDataCollector::class)
|
||||
->args([
|
||||
service('logger')->ignoreOnInvalid(),
|
||||
\sprintf('%s/%s', param('kernel.build_dir'), param('kernel.container_class')),
|
||||
service('.virtual_request_stack')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('monolog.logger', ['channel' => 'profiler'])
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/logger.html.twig', 'id' => 'logger', 'priority' => 300])
|
||||
|
||||
->set('data_collector.time', TimeDataCollector::class)
|
||||
->args([
|
||||
service('kernel')->ignoreOnInvalid(),
|
||||
service('debug.stopwatch')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/time.html.twig', 'id' => 'time', 'priority' => 330])
|
||||
|
||||
->set('data_collector.memory', MemoryDataCollector::class)
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/memory.html.twig', 'id' => 'memory', 'priority' => 325])
|
||||
|
||||
->set('data_collector.router', RouterDataCollector::class)
|
||||
->tag('kernel.event_listener', ['event' => KernelEvents::CONTROLLER, 'method' => 'onKernelController'])
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/router.html.twig', 'id' => 'router', 'priority' => 285])
|
||||
|
||||
->set('.data_collector.command', CommandDataCollector::class)
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/command.html.twig', 'id' => 'command', 'priority' => 335])
|
||||
;
|
||||
};
|
||||
411
vendor/symfony/framework-bundle/Resources/config/console.php
vendored
Normal file
411
vendor/symfony/framework-bundle/Resources/config/console.php
vendored
Normal file
@@ -0,0 +1,411 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Command\AboutCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\AssetsInstallCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\CacheClearCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\CachePoolClearCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\CachePoolDeleteCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\CachePoolInvalidateTagsCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\CachePoolListCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\CachePoolPruneCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\CacheWarmupCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ConfigDebugCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ConfigDumpReferenceCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerDebugCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\ContainerLintCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\DebugAutowiringCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\EventDispatcherDebugCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\RouterDebugCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\RouterMatchCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\SecretsDecryptToLocalCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\SecretsEncryptFromLocalCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\SecretsGenerateKeysCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\SecretsListCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\SecretsRemoveCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\SecretsRevealCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\SecretsSetCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\TranslationDebugCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\TranslationExtractCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\WorkflowDumpCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Command\YamlLintCommand;
|
||||
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||
use Symfony\Bundle\FrameworkBundle\EventListener\SuggestMissingPackageSubscriber;
|
||||
use Symfony\Component\Console\EventListener\ErrorListener;
|
||||
use Symfony\Component\Console\Messenger\RunCommandMessageHandler;
|
||||
use Symfony\Component\Dotenv\Command\DebugCommand as DotenvDebugCommand;
|
||||
use Symfony\Component\ErrorHandler\Command\ErrorDumpCommand;
|
||||
use Symfony\Component\Messenger\Command\ConsumeMessagesCommand;
|
||||
use Symfony\Component\Messenger\Command\DebugCommand as MessengerDebugCommand;
|
||||
use Symfony\Component\Messenger\Command\FailedMessagesRemoveCommand;
|
||||
use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand;
|
||||
use Symfony\Component\Messenger\Command\FailedMessagesShowCommand;
|
||||
use Symfony\Component\Messenger\Command\SetupTransportsCommand;
|
||||
use Symfony\Component\Messenger\Command\StatsCommand;
|
||||
use Symfony\Component\Messenger\Command\StopWorkersCommand;
|
||||
use Symfony\Component\Scheduler\Command\DebugCommand as SchedulerDebugCommand;
|
||||
use Symfony\Component\Serializer\Command\DebugCommand as SerializerDebugCommand;
|
||||
use Symfony\Component\Translation\Command\TranslationLintCommand;
|
||||
use Symfony\Component\Translation\Command\TranslationPullCommand;
|
||||
use Symfony\Component\Translation\Command\TranslationPushCommand;
|
||||
use Symfony\Component\Translation\Command\XliffLintCommand;
|
||||
use Symfony\Component\Validator\Command\DebugCommand as ValidatorDebugCommand;
|
||||
use Symfony\WebpackEncoreBundle\Asset\EntrypointLookupInterface;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('console.error_listener', ErrorListener::class)
|
||||
->args([
|
||||
service('logger')->nullOnInvalid(),
|
||||
])
|
||||
->tag('kernel.event_subscriber')
|
||||
->tag('monolog.logger', ['channel' => 'console'])
|
||||
|
||||
->set('console.suggest_missing_package_subscriber', SuggestMissingPackageSubscriber::class)
|
||||
->tag('kernel.event_subscriber')
|
||||
|
||||
->set('console.command.about', AboutCommand::class)
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.assets_install', AssetsInstallCommand::class)
|
||||
->args([
|
||||
service('filesystem'),
|
||||
param('kernel.project_dir'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.cache_clear', CacheClearCommand::class)
|
||||
->args([
|
||||
service('cache_clearer'),
|
||||
service('filesystem'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.cache_pool_clear', CachePoolClearCommand::class)
|
||||
->args([
|
||||
service('cache.global_clearer'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.cache_pool_prune', CachePoolPruneCommand::class)
|
||||
->args([
|
||||
[],
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.cache_pool_invalidate_tags', CachePoolInvalidateTagsCommand::class)
|
||||
->args([
|
||||
tagged_locator('cache.taggable', 'pool'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.cache_pool_delete', CachePoolDeleteCommand::class)
|
||||
->args([
|
||||
service('cache.global_clearer'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.cache_pool_list', CachePoolListCommand::class)
|
||||
->args([
|
||||
null,
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.cache_warmup', CacheWarmupCommand::class)
|
||||
->args([
|
||||
service('cache_warmer'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.config_debug', ConfigDebugCommand::class)
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.config_dump_reference', ConfigDumpReferenceCommand::class)
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.container_debug', ContainerDebugCommand::class)
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.container_lint', ContainerLintCommand::class)
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.debug_autowiring', DebugAutowiringCommand::class)
|
||||
->args([
|
||||
null,
|
||||
service('debug.file_link_formatter')->nullOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.dotenv_debug', DotenvDebugCommand::class)
|
||||
->args([
|
||||
param('kernel.environment'),
|
||||
param('kernel.project_dir'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.event_dispatcher_debug', EventDispatcherDebugCommand::class)
|
||||
->args([
|
||||
tagged_locator('event_dispatcher.dispatcher', 'name'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.messenger_consume_messages', ConsumeMessagesCommand::class)
|
||||
->args([
|
||||
abstract_arg('Routable message bus'),
|
||||
service('messenger.receiver_locator'),
|
||||
service('event_dispatcher'),
|
||||
service('logger')->nullOnInvalid(),
|
||||
[], // Receiver names
|
||||
service('messenger.listener.reset_services')->nullOnInvalid(),
|
||||
[], // Bus names
|
||||
service('messenger.rate_limiter_locator')->nullOnInvalid(),
|
||||
null,
|
||||
])
|
||||
->tag('console.command')
|
||||
->tag('monolog.logger', ['channel' => 'messenger'])
|
||||
|
||||
->set('console.command.messenger_setup_transports', SetupTransportsCommand::class)
|
||||
->args([
|
||||
service('messenger.receiver_locator'),
|
||||
[], // Receiver names
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.messenger_debug', MessengerDebugCommand::class)
|
||||
->args([
|
||||
[], // Message to handlers mapping
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.messenger_stop_workers', StopWorkersCommand::class)
|
||||
->args([
|
||||
service('cache.messenger.restart_workers_signal'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.messenger_failed_messages_retry', FailedMessagesRetryCommand::class)
|
||||
->args([
|
||||
abstract_arg('Default failure receiver name'),
|
||||
abstract_arg('Receivers'),
|
||||
service('messenger.routable_message_bus'),
|
||||
service('event_dispatcher'),
|
||||
service('logger')->nullOnInvalid(),
|
||||
service('messenger.transport.native_php_serializer')->nullOnInvalid(),
|
||||
null,
|
||||
])
|
||||
->tag('console.command')
|
||||
->tag('monolog.logger', ['channel' => 'messenger'])
|
||||
|
||||
->set('console.command.messenger_failed_messages_show', FailedMessagesShowCommand::class)
|
||||
->args([
|
||||
abstract_arg('Default failure receiver name'),
|
||||
abstract_arg('Receivers'),
|
||||
service('messenger.transport.native_php_serializer')->nullOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.messenger_failed_messages_remove', FailedMessagesRemoveCommand::class)
|
||||
->args([
|
||||
abstract_arg('Default failure receiver name'),
|
||||
abstract_arg('Receivers'),
|
||||
service('messenger.transport.native_php_serializer')->nullOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.messenger_stats', StatsCommand::class)
|
||||
->args([
|
||||
service('messenger.receiver_locator'),
|
||||
abstract_arg('Receivers names'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.scheduler_debug', SchedulerDebugCommand::class)
|
||||
->args([
|
||||
tagged_locator('scheduler.schedule_provider', 'name'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.router_debug', RouterDebugCommand::class)
|
||||
->args([
|
||||
service('router'),
|
||||
service('debug.file_link_formatter')->nullOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.router_match', RouterMatchCommand::class)
|
||||
->args([
|
||||
service('router'),
|
||||
tagged_iterator('routing.expression_language_provider'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.serializer_debug', SerializerDebugCommand::class)
|
||||
->args([
|
||||
service('serializer.mapping.class_metadata_factory'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.translation_debug', TranslationDebugCommand::class)
|
||||
->args([
|
||||
service('translator'),
|
||||
service('translation.reader'),
|
||||
service('translation.extractor'),
|
||||
param('translator.default_path'),
|
||||
null, // twig.default_path
|
||||
[], // Translator paths
|
||||
[], // Twig paths
|
||||
param('kernel.enabled_locales'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.translation_extract', TranslationExtractCommand::class)
|
||||
->args([
|
||||
service('translation.writer'),
|
||||
service('translation.reader'),
|
||||
service('translation.extractor'),
|
||||
param('kernel.default_locale'),
|
||||
param('translator.default_path'),
|
||||
null, // twig.default_path
|
||||
[], // Translator paths
|
||||
[], // Twig paths
|
||||
param('kernel.enabled_locales'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.validator_debug', ValidatorDebugCommand::class)
|
||||
->args([
|
||||
service('validator'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.translation_pull', TranslationPullCommand::class)
|
||||
->args([
|
||||
service('translation.provider_collection'),
|
||||
service('translation.writer'),
|
||||
service('translation.reader'),
|
||||
param('kernel.default_locale'),
|
||||
[], // Translator paths
|
||||
[], // Enabled locales
|
||||
])
|
||||
->tag('console.command', ['command' => 'translation:pull'])
|
||||
|
||||
->set('console.command.translation_push', TranslationPushCommand::class)
|
||||
->args([
|
||||
service('translation.provider_collection'),
|
||||
service('translation.reader'),
|
||||
[], // Translator paths
|
||||
[], // Enabled locales
|
||||
])
|
||||
->tag('console.command', ['command' => 'translation:push'])
|
||||
|
||||
->set('console.command.workflow_dump', WorkflowDumpCommand::class)
|
||||
->args([
|
||||
tagged_locator('workflow', 'name'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.xliff_lint', XliffLintCommand::class)
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.yaml_lint', YamlLintCommand::class)
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.translation_lint', TranslationLintCommand::class)
|
||||
->args([
|
||||
service('translator'),
|
||||
param('kernel.enabled_locales'),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.form_debug', \Symfony\Component\Form\Command\DebugCommand::class)
|
||||
->args([
|
||||
service('form.registry'),
|
||||
[], // All form types namespaces are stored here by FormPass
|
||||
[], // All services form types are stored here by FormPass
|
||||
[], // All type extensions are stored here by FormPass
|
||||
[], // All type guessers are stored here by FormPass
|
||||
service('debug.file_link_formatter')->nullOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.secrets_set', SecretsSetCommand::class)
|
||||
->args([
|
||||
service('secrets.vault'),
|
||||
service('secrets.local_vault')->nullOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.secrets_remove', SecretsRemoveCommand::class)
|
||||
->args([
|
||||
service('secrets.vault'),
|
||||
service('secrets.local_vault')->nullOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.secrets_generate_key', SecretsGenerateKeysCommand::class)
|
||||
->args([
|
||||
service('secrets.vault'),
|
||||
service('secrets.local_vault')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.secrets_list', SecretsListCommand::class)
|
||||
->args([
|
||||
service('secrets.vault'),
|
||||
service('secrets.local_vault')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.secrets_reveal', SecretsRevealCommand::class)
|
||||
->args([
|
||||
service('secrets.vault'),
|
||||
service('secrets.local_vault')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.secrets_decrypt_to_local', SecretsDecryptToLocalCommand::class)
|
||||
->args([
|
||||
service('secrets.vault'),
|
||||
service('secrets.local_vault')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.secrets_encrypt_from_local', SecretsEncryptFromLocalCommand::class)
|
||||
->args([
|
||||
service('secrets.vault'),
|
||||
service('secrets.local_vault')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.command.error_dumper', ErrorDumpCommand::class)
|
||||
->args([
|
||||
service('filesystem'),
|
||||
service('error_renderer.html'),
|
||||
service(EntrypointLookupInterface::class)->nullOnInvalid(),
|
||||
])
|
||||
->tag('console.command')
|
||||
|
||||
->set('console.messenger.application', Application::class)
|
||||
->share(false)
|
||||
->call('setAutoExit', [false])
|
||||
->args([
|
||||
service('kernel'),
|
||||
])
|
||||
|
||||
->set('console.messenger.execute_command_handler', RunCommandMessageHandler::class)
|
||||
->args([
|
||||
service('console.messenger.application'),
|
||||
])
|
||||
->tag('messenger.message_handler')
|
||||
;
|
||||
};
|
||||
51
vendor/symfony/framework-bundle/Resources/config/debug.php
vendored
Normal file
51
vendor/symfony/framework-bundle/Resources/config/debug.php
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\NotTaggedControllerValueResolver;
|
||||
use Symfony\Component\HttpKernel\Controller\TraceableArgumentResolver;
|
||||
use Symfony\Component\HttpKernel\Controller\TraceableControllerResolver;
|
||||
use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('debug.event_dispatcher', TraceableEventDispatcher::class)
|
||||
->decorate('event_dispatcher')
|
||||
->args([
|
||||
service('debug.event_dispatcher.inner'),
|
||||
service('debug.stopwatch'),
|
||||
service('logger')->nullOnInvalid(),
|
||||
service('.virtual_request_stack')->nullOnInvalid(),
|
||||
service('profiler.is_disabled_state_checker')->nullOnInvalid(),
|
||||
])
|
||||
->tag('monolog.logger', ['channel' => 'event'])
|
||||
->tag('kernel.reset', ['method' => 'reset'])
|
||||
|
||||
->set('debug.controller_resolver', TraceableControllerResolver::class)
|
||||
->decorate('controller_resolver')
|
||||
->args([
|
||||
service('debug.controller_resolver.inner'),
|
||||
service('debug.stopwatch'),
|
||||
])
|
||||
|
||||
->set('debug.argument_resolver', TraceableArgumentResolver::class)
|
||||
->decorate('argument_resolver')
|
||||
->args([
|
||||
service('debug.argument_resolver.inner'),
|
||||
service('debug.stopwatch'),
|
||||
])
|
||||
|
||||
->set('argument_resolver.not_tagged_controller', NotTaggedControllerValueResolver::class)
|
||||
->args([abstract_arg('Controller argument, set in FrameworkExtension')])
|
||||
->tag('controller.argument_value_resolver', ['priority' => -200])
|
||||
;
|
||||
};
|
||||
43
vendor/symfony/framework-bundle/Resources/config/debug_prod.php
vendored
Normal file
43
vendor/symfony/framework-bundle/Resources/config/debug_prod.php
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\FileLinkFormatter;
|
||||
use Symfony\Component\HttpKernel\Debug\ErrorHandlerConfigurator;
|
||||
use Symfony\Component\HttpKernel\EventListener\DebugHandlersListener;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->parameters()->set('debug.error_handler.throw_at', -1);
|
||||
|
||||
$container->services()
|
||||
->set('debug.error_handler_configurator', ErrorHandlerConfigurator::class)
|
||||
->public()
|
||||
->args([
|
||||
service('logger')->nullOnInvalid(),
|
||||
null, // Log levels map for enabled error levels
|
||||
param('debug.error_handler.throw_at'),
|
||||
param('kernel.debug'),
|
||||
param('kernel.debug'),
|
||||
null, // Deprecation logger if different from the one above
|
||||
])
|
||||
->tag('monolog.logger', ['channel' => 'php'])
|
||||
|
||||
->set('debug.debug_handlers_listener', DebugHandlersListener::class)
|
||||
->args([null, param('kernel.runtime_mode.web')])
|
||||
->tag('kernel.event_subscriber')
|
||||
|
||||
->set('debug.file_link_formatter', FileLinkFormatter::class)
|
||||
->args([param('debug.file_link_format')])
|
||||
|
||||
->alias(FileLinkFormatter::class, 'debug.file_link_formatter')
|
||||
;
|
||||
};
|
||||
38
vendor/symfony/framework-bundle/Resources/config/error_renderer.php
vendored
Normal file
38
vendor/symfony/framework-bundle/Resources/config/error_renderer.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('error_handler.error_renderer.html', HtmlErrorRenderer::class)
|
||||
->args([
|
||||
inline_service()
|
||||
->factory([HtmlErrorRenderer::class, 'isDebug'])
|
||||
->args([
|
||||
service('request_stack'),
|
||||
param('kernel.debug'),
|
||||
]),
|
||||
param('kernel.charset'),
|
||||
service('debug.file_link_formatter')->nullOnInvalid(),
|
||||
param('kernel.project_dir'),
|
||||
inline_service()
|
||||
->factory([HtmlErrorRenderer::class, 'getAndCleanOutputBuffer'])
|
||||
->args([service('request_stack')]),
|
||||
service('logger')->nullOnInvalid(),
|
||||
])
|
||||
|
||||
->alias('error_renderer.html', 'error_handler.error_renderer.html')
|
||||
->alias('error_renderer', 'error_renderer.html')
|
||||
;
|
||||
};
|
||||
25
vendor/symfony/framework-bundle/Resources/config/esi.php
vendored
Normal file
25
vendor/symfony/framework-bundle/Resources/config/esi.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\HttpKernel\EventListener\SurrogateListener;
|
||||
use Symfony\Component\HttpKernel\HttpCache\Esi;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('esi', Esi::class)
|
||||
|
||||
->set('esi_listener', SurrogateListener::class)
|
||||
->args([service('esi')->ignoreOnInvalid()])
|
||||
->tag('kernel.event_subscriber')
|
||||
;
|
||||
};
|
||||
154
vendor/symfony/framework-bundle/Resources/config/form.php
vendored
Normal file
154
vendor/symfony/framework-bundle/Resources/config/form.php
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
|
||||
use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ColorType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FileType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\FormType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TransformationFailureExtension;
|
||||
use Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension;
|
||||
use Symfony\Component\Form\Extension\HtmlSanitizer\Type\TextTypeHtmlSanitizerExtension;
|
||||
use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler;
|
||||
use Symfony\Component\Form\Extension\HttpFoundation\Type\FormTypeHttpFoundationExtension;
|
||||
use Symfony\Component\Form\Extension\Validator\Type\FormTypeValidatorExtension;
|
||||
use Symfony\Component\Form\Extension\Validator\Type\RepeatedTypeValidatorExtension;
|
||||
use Symfony\Component\Form\Extension\Validator\Type\SubmitTypeValidatorExtension;
|
||||
use Symfony\Component\Form\Extension\Validator\Type\UploadValidatorExtension;
|
||||
use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser;
|
||||
use Symfony\Component\Form\FormFactory;
|
||||
use Symfony\Component\Form\FormFactoryInterface;
|
||||
use Symfony\Component\Form\FormRegistry;
|
||||
use Symfony\Component\Form\FormRegistryInterface;
|
||||
use Symfony\Component\Form\ResolvedFormTypeFactory;
|
||||
use Symfony\Component\Form\ResolvedFormTypeFactoryInterface;
|
||||
use Symfony\Component\Form\Util\ServerParams;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('form.resolved_type_factory', ResolvedFormTypeFactory::class)
|
||||
|
||||
->alias(ResolvedFormTypeFactoryInterface::class, 'form.resolved_type_factory')
|
||||
|
||||
->set('form.registry', FormRegistry::class)
|
||||
->args([
|
||||
[
|
||||
/*
|
||||
* We don't need to be able to add more extensions.
|
||||
* more types can be registered with the form.type tag
|
||||
* more type extensions can be registered with the form.type_extension tag
|
||||
* more type_guessers can be registered with the form.type_guesser tag
|
||||
*/
|
||||
service('form.extension'),
|
||||
],
|
||||
service('form.resolved_type_factory'),
|
||||
])
|
||||
|
||||
->alias(FormRegistryInterface::class, 'form.registry')
|
||||
|
||||
->set('form.factory', FormFactory::class)
|
||||
->args([service('form.registry')])
|
||||
|
||||
->alias(FormFactoryInterface::class, 'form.factory')
|
||||
|
||||
->set('form.extension', DependencyInjectionExtension::class)
|
||||
->args([
|
||||
abstract_arg('All services with tag "form.type" are stored in a service locator by FormPass'),
|
||||
abstract_arg('All services with tag "form.type_extension" are stored here by FormPass'),
|
||||
abstract_arg('All services with tag "form.type_guesser" are stored here by FormPass'),
|
||||
])
|
||||
|
||||
->set('form.type_guesser.validator', ValidatorTypeGuesser::class)
|
||||
->args([service('validator.mapping.class_metadata_factory')])
|
||||
->tag('form.type_guesser')
|
||||
|
||||
->alias('form.property_accessor', 'property_accessor')
|
||||
|
||||
->set('form.choice_list_factory.default', DefaultChoiceListFactory::class)
|
||||
|
||||
->set('form.choice_list_factory.property_access', PropertyAccessDecorator::class)
|
||||
->args([
|
||||
service('form.choice_list_factory.default'),
|
||||
service('form.property_accessor'),
|
||||
])
|
||||
|
||||
->set('form.choice_list_factory.cached', CachingFactoryDecorator::class)
|
||||
->args([service('form.choice_list_factory.property_access')])
|
||||
->tag('kernel.reset', ['method' => 'reset'])
|
||||
|
||||
->alias('form.choice_list_factory', 'form.choice_list_factory.cached')
|
||||
|
||||
->set('form.type.form', FormType::class)
|
||||
->args([service('form.property_accessor')])
|
||||
->tag('form.type')
|
||||
|
||||
->set('form.type.choice', ChoiceType::class)
|
||||
->args([
|
||||
service('form.choice_list_factory'),
|
||||
service('translator')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('form.type')
|
||||
|
||||
->set('form.type.file', FileType::class)
|
||||
->args([service('translator')->ignoreOnInvalid()])
|
||||
->tag('form.type')
|
||||
|
||||
->set('form.type.color', ColorType::class)
|
||||
->args([service('translator')->ignoreOnInvalid()])
|
||||
->tag('form.type')
|
||||
|
||||
->set('form.type_extension.form.transformation_failure_handling', TransformationFailureExtension::class)
|
||||
->args([service('translator')->ignoreOnInvalid()])
|
||||
->tag('form.type_extension', ['extended-type' => FormType::class])
|
||||
|
||||
->set('form.type_extension.form.html_sanitizer', TextTypeHtmlSanitizerExtension::class)
|
||||
->args([tagged_locator('html_sanitizer', 'sanitizer')])
|
||||
->tag('form.type_extension', ['extended-type' => TextType::class])
|
||||
|
||||
->set('form.type_extension.form.http_foundation', FormTypeHttpFoundationExtension::class)
|
||||
->args([service('form.type_extension.form.request_handler')])
|
||||
->tag('form.type_extension')
|
||||
|
||||
->set('form.type_extension.form.request_handler', HttpFoundationRequestHandler::class)
|
||||
->args([service('form.server_params')])
|
||||
|
||||
->set('form.server_params', ServerParams::class)
|
||||
->args([service('request_stack')])
|
||||
|
||||
->set('form.type_extension.form.validator', FormTypeValidatorExtension::class)
|
||||
->args([
|
||||
service('validator'),
|
||||
false,
|
||||
service('twig.form.renderer')->ignoreOnInvalid(),
|
||||
service('translator')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('form.type_extension', ['extended-type' => FormType::class])
|
||||
|
||||
->set('form.type_extension.repeated.validator', RepeatedTypeValidatorExtension::class)
|
||||
->tag('form.type_extension')
|
||||
|
||||
->set('form.type_extension.submit.validator', SubmitTypeValidatorExtension::class)
|
||||
->tag('form.type_extension', ['extended-type' => SubmitType::class])
|
||||
|
||||
->set('form.type_extension.upload.validator', UploadValidatorExtension::class)
|
||||
->args([
|
||||
service('translator'),
|
||||
param('validator.translation_domain'),
|
||||
])
|
||||
->tag('form.type_extension')
|
||||
;
|
||||
};
|
||||
31
vendor/symfony/framework-bundle/Resources/config/form_csrf.php
vendored
Normal file
31
vendor/symfony/framework-bundle/Resources/config/form_csrf.php
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\Form\Extension\Csrf\Type\FormTypeCsrfExtension;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('form.type_extension.csrf', FormTypeCsrfExtension::class)
|
||||
->args([
|
||||
service('security.csrf.token_manager'),
|
||||
param('form.type_extension.csrf.enabled'),
|
||||
param('form.type_extension.csrf.field_name'),
|
||||
service('translator')->nullOnInvalid(),
|
||||
param('validator.translation_domain'),
|
||||
service('form.server_params'),
|
||||
param('form.type_extension.csrf.field_attr'),
|
||||
param('.form.type_extension.csrf.token_id'),
|
||||
])
|
||||
->tag('form.type_extension')
|
||||
;
|
||||
};
|
||||
38
vendor/symfony/framework-bundle/Resources/config/form_debug.php
vendored
Normal file
38
vendor/symfony/framework-bundle/Resources/config/form_debug.php
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\Form\Extension\DataCollector\FormDataCollector;
|
||||
use Symfony\Component\Form\Extension\DataCollector\FormDataExtractor;
|
||||
use Symfony\Component\Form\Extension\DataCollector\Proxy\ResolvedTypeFactoryDataCollectorProxy;
|
||||
use Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension;
|
||||
use Symfony\Component\Form\ResolvedFormTypeFactory;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('form.resolved_type_factory', ResolvedTypeFactoryDataCollectorProxy::class)
|
||||
->args([
|
||||
inline_service(ResolvedFormTypeFactory::class),
|
||||
service('data_collector.form'),
|
||||
])
|
||||
|
||||
->set('form.type_extension.form.data_collector', DataCollectorTypeExtension::class)
|
||||
->args([service('data_collector.form')])
|
||||
->tag('form.type_extension')
|
||||
|
||||
->set('data_collector.form.extractor', FormDataExtractor::class)
|
||||
|
||||
->set('data_collector.form', FormDataCollector::class)
|
||||
->args([service('data_collector.form.extractor')])
|
||||
->tag('data_collector', ['template' => '@WebProfiler/Collector/form.html.twig', 'id' => 'form', 'priority' => 310])
|
||||
;
|
||||
};
|
||||
22
vendor/symfony/framework-bundle/Resources/config/fragment_listener.php
vendored
Normal file
22
vendor/symfony/framework-bundle/Resources/config/fragment_listener.php
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\HttpKernel\EventListener\FragmentListener;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('fragment.listener', FragmentListener::class)
|
||||
->args([service('uri_signer'), param('fragment.path')])
|
||||
->tag('kernel.event_subscriber')
|
||||
;
|
||||
};
|
||||
71
vendor/symfony/framework-bundle/Resources/config/fragment_renderer.php
vendored
Normal file
71
vendor/symfony/framework-bundle/Resources/config/fragment_renderer.php
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\LazyLoadingFragmentHandler;
|
||||
use Symfony\Component\HttpKernel\Fragment\EsiFragmentRenderer;
|
||||
use Symfony\Component\HttpKernel\Fragment\FragmentUriGenerator;
|
||||
use Symfony\Component\HttpKernel\Fragment\FragmentUriGeneratorInterface;
|
||||
use Symfony\Component\HttpKernel\Fragment\HIncludeFragmentRenderer;
|
||||
use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer;
|
||||
use Symfony\Component\HttpKernel\Fragment\SsiFragmentRenderer;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->parameters()
|
||||
->set('fragment.renderer.hinclude.global_template', null)
|
||||
->set('fragment.path', '/_fragment')
|
||||
;
|
||||
|
||||
$container->services()
|
||||
->set('fragment.handler', LazyLoadingFragmentHandler::class)
|
||||
->args([
|
||||
abstract_arg('fragment renderer locator'),
|
||||
service('request_stack'),
|
||||
param('kernel.debug'),
|
||||
])
|
||||
|
||||
->set('fragment.uri_generator', FragmentUriGenerator::class)
|
||||
->args([param('fragment.path'), service('uri_signer'), service('request_stack')])
|
||||
->alias(FragmentUriGeneratorInterface::class, 'fragment.uri_generator')
|
||||
|
||||
->set('fragment.renderer.inline', InlineFragmentRenderer::class)
|
||||
->args([service('http_kernel'), service('event_dispatcher')])
|
||||
->call('setFragmentPath', [param('fragment.path')])
|
||||
->tag('kernel.fragment_renderer', ['alias' => 'inline'])
|
||||
|
||||
->set('fragment.renderer.hinclude', HIncludeFragmentRenderer::class)
|
||||
->args([
|
||||
service('twig')->nullOnInvalid(),
|
||||
service('uri_signer'),
|
||||
param('fragment.renderer.hinclude.global_template'),
|
||||
])
|
||||
->call('setFragmentPath', [param('fragment.path')])
|
||||
|
||||
->set('fragment.renderer.esi', EsiFragmentRenderer::class)
|
||||
->args([
|
||||
service('esi')->nullOnInvalid(),
|
||||
service('fragment.renderer.inline'),
|
||||
service('uri_signer'),
|
||||
])
|
||||
->call('setFragmentPath', [param('fragment.path')])
|
||||
->tag('kernel.fragment_renderer', ['alias' => 'esi'])
|
||||
|
||||
->set('fragment.renderer.ssi', SsiFragmentRenderer::class)
|
||||
->args([
|
||||
service('ssi')->nullOnInvalid(),
|
||||
service('fragment.renderer.inline'),
|
||||
service('uri_signer'),
|
||||
])
|
||||
->call('setFragmentPath', [param('fragment.path')])
|
||||
->tag('kernel.fragment_renderer', ['alias' => 'ssi'])
|
||||
;
|
||||
};
|
||||
30
vendor/symfony/framework-bundle/Resources/config/html_sanitizer.php
vendored
Normal file
30
vendor/symfony/framework-bundle/Resources/config/html_sanitizer.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\HtmlSanitizer\HtmlSanitizer;
|
||||
use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig;
|
||||
use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('html_sanitizer.config.default', HtmlSanitizerConfig::class)
|
||||
->call('allowSafeElements', [], true)
|
||||
|
||||
->set('html_sanitizer.sanitizer.default', HtmlSanitizer::class)
|
||||
->args([service('html_sanitizer.config.default')])
|
||||
->tag('html_sanitizer', ['sanitizer' => 'default'])
|
||||
|
||||
->alias('html_sanitizer', 'html_sanitizer.sanitizer.default')
|
||||
->alias(HtmlSanitizerInterface::class, 'html_sanitizer')
|
||||
;
|
||||
};
|
||||
100
vendor/symfony/framework-bundle/Resources/config/http_client.php
vendored
Normal file
100
vendor/symfony/framework-bundle/Resources/config/http_client.php
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Http\Client\HttpAsyncClient;
|
||||
use Psr\Http\Client\ClientInterface;
|
||||
use Psr\Http\Message\ResponseFactoryInterface;
|
||||
use Psr\Http\Message\StreamFactoryInterface;
|
||||
use Symfony\Component\HttpClient\HttpClient;
|
||||
use Symfony\Component\HttpClient\HttplugClient;
|
||||
use Symfony\Component\HttpClient\Messenger\PingWebhookMessageHandler;
|
||||
use Symfony\Component\HttpClient\Psr18Client;
|
||||
use Symfony\Component\HttpClient\Retry\GenericRetryStrategy;
|
||||
use Symfony\Component\HttpClient\UriTemplateHttpClient;
|
||||
use Symfony\Contracts\HttpClient\HttpClientInterface;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('http_client.transport', HttpClientInterface::class)
|
||||
->factory([HttpClient::class, 'create'])
|
||||
->args([
|
||||
[], // default options
|
||||
abstract_arg('max host connections'),
|
||||
])
|
||||
->call('setLogger', [service('logger')->ignoreOnInvalid()])
|
||||
->tag('monolog.logger', ['channel' => 'http_client'])
|
||||
->tag('kernel.reset', ['method' => 'reset', 'on_invalid' => 'ignore'])
|
||||
|
||||
->set('http_client', HttpClientInterface::class)
|
||||
->factory('current')
|
||||
->args([[service('http_client.transport')]])
|
||||
->tag('http_client.client')
|
||||
->tag('kernel.reset', ['method' => 'reset', 'on_invalid' => 'ignore'])
|
||||
|
||||
->alias(HttpClientInterface::class, 'http_client')
|
||||
|
||||
->set('psr18.http_client', Psr18Client::class)
|
||||
->args([
|
||||
service('http_client'),
|
||||
service(ResponseFactoryInterface::class)->ignoreOnInvalid(),
|
||||
service(StreamFactoryInterface::class)->ignoreOnInvalid(),
|
||||
])
|
||||
|
||||
->alias(ClientInterface::class, 'psr18.http_client')
|
||||
|
||||
->set('httplug.http_client', HttplugClient::class)
|
||||
->args([
|
||||
service('http_client'),
|
||||
service(ResponseFactoryInterface::class)->ignoreOnInvalid(),
|
||||
service(StreamFactoryInterface::class)->ignoreOnInvalid(),
|
||||
])
|
||||
|
||||
->alias(HttpAsyncClient::class, 'httplug.http_client')
|
||||
|
||||
->set('http_client.abstract_retry_strategy', GenericRetryStrategy::class)
|
||||
->abstract()
|
||||
->args([
|
||||
abstract_arg('http codes'),
|
||||
abstract_arg('delay ms'),
|
||||
abstract_arg('multiplier'),
|
||||
abstract_arg('max delay ms'),
|
||||
abstract_arg('jitter'),
|
||||
])
|
||||
|
||||
->set('http_client.uri_template', UriTemplateHttpClient::class)
|
||||
->decorate('http_client', null, 7) // Between TraceableHttpClient (5) and RetryableHttpClient (10)
|
||||
->args([
|
||||
service('.inner'),
|
||||
service('http_client.uri_template_expander')->nullOnInvalid(),
|
||||
abstract_arg('default vars'),
|
||||
])
|
||||
|
||||
->set('http_client.uri_template_expander.guzzle', \Closure::class)
|
||||
->factory([\Closure::class, 'fromCallable'])
|
||||
->args([
|
||||
[\GuzzleHttp\UriTemplate\UriTemplate::class, 'expand'],
|
||||
])
|
||||
|
||||
->set('http_client.uri_template_expander.rize', \Closure::class)
|
||||
->factory([\Closure::class, 'fromCallable'])
|
||||
->args([
|
||||
[inline_service(\Rize\UriTemplate::class), 'expand'],
|
||||
])
|
||||
|
||||
->set('http_client.messenger.ping_webhook_handler', PingWebhookMessageHandler::class)
|
||||
->args([
|
||||
service('http_client'),
|
||||
])
|
||||
->tag('messenger.message_handler')
|
||||
;
|
||||
};
|
||||
25
vendor/symfony/framework-bundle/Resources/config/http_client_debug.php
vendored
Normal file
25
vendor/symfony/framework-bundle/Resources/config/http_client_debug.php
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\HttpClient\DataCollector\HttpClientDataCollector;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('data_collector.http_client', HttpClientDataCollector::class)
|
||||
->tag('data_collector', [
|
||||
'template' => '@WebProfiler/Collector/http_client.html.twig',
|
||||
'id' => 'http_client',
|
||||
'priority' => 250,
|
||||
])
|
||||
;
|
||||
};
|
||||
24
vendor/symfony/framework-bundle/Resources/config/identity_translator.php
vendored
Normal file
24
vendor/symfony/framework-bundle/Resources/config/identity_translator.php
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\Translation\IdentityTranslator;
|
||||
use Symfony\Contracts\Translation\TranslatorInterface;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('translator', IdentityTranslator::class)
|
||||
->alias(TranslatorInterface::class, 'translator')
|
||||
|
||||
->set('identity_translator', IdentityTranslator::class)
|
||||
;
|
||||
};
|
||||
119
vendor/symfony/framework-bundle/Resources/config/json_streamer.php
vendored
Normal file
119
vendor/symfony/framework-bundle/Resources/config/json_streamer.php
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\JsonStreamer\CacheWarmer\LazyGhostCacheWarmer;
|
||||
use Symfony\Component\JsonStreamer\CacheWarmer\StreamerCacheWarmer;
|
||||
use Symfony\Component\JsonStreamer\JsonStreamReader;
|
||||
use Symfony\Component\JsonStreamer\JsonStreamWriter;
|
||||
use Symfony\Component\JsonStreamer\Mapping\GenericTypePropertyMetadataLoader;
|
||||
use Symfony\Component\JsonStreamer\Mapping\PropertyMetadataLoader;
|
||||
use Symfony\Component\JsonStreamer\Mapping\Read\AttributePropertyMetadataLoader as ReadAttributePropertyMetadataLoader;
|
||||
use Symfony\Component\JsonStreamer\Mapping\Read\DateTimeTypePropertyMetadataLoader as ReadDateTimeTypePropertyMetadataLoader;
|
||||
use Symfony\Component\JsonStreamer\Mapping\Write\AttributePropertyMetadataLoader as WriteAttributePropertyMetadataLoader;
|
||||
use Symfony\Component\JsonStreamer\Mapping\Write\DateTimeTypePropertyMetadataLoader as WriteDateTimeTypePropertyMetadataLoader;
|
||||
use Symfony\Component\JsonStreamer\ValueTransformer\DateTimeToStringValueTransformer;
|
||||
use Symfony\Component\JsonStreamer\ValueTransformer\StringToDateTimeValueTransformer;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
// stream reader/writer
|
||||
->set('json_streamer.stream_writer', JsonStreamWriter::class)
|
||||
->args([
|
||||
tagged_locator('json_streamer.value_transformer'),
|
||||
service('json_streamer.write.property_metadata_loader'),
|
||||
param('.json_streamer.stream_writers_dir'),
|
||||
])
|
||||
->set('json_streamer.stream_reader', JsonStreamReader::class)
|
||||
->args([
|
||||
tagged_locator('json_streamer.value_transformer'),
|
||||
service('json_streamer.read.property_metadata_loader'),
|
||||
param('.json_streamer.stream_readers_dir'),
|
||||
param('.json_streamer.lazy_ghosts_dir'),
|
||||
])
|
||||
->alias(JsonStreamWriter::class, 'json_streamer.stream_writer')
|
||||
->alias(JsonStreamReader::class, 'json_streamer.stream_reader')
|
||||
|
||||
// metadata
|
||||
->set('json_streamer.write.property_metadata_loader', PropertyMetadataLoader::class)
|
||||
->args([
|
||||
service('type_info.resolver'),
|
||||
])
|
||||
->set('.json_streamer.write.property_metadata_loader.generic', GenericTypePropertyMetadataLoader::class)
|
||||
->decorate('json_streamer.write.property_metadata_loader')
|
||||
->args([
|
||||
service('.inner'),
|
||||
service('type_info.type_context_factory'),
|
||||
])
|
||||
->set('.json_streamer.write.property_metadata_loader.date_time', WriteDateTimeTypePropertyMetadataLoader::class)
|
||||
->decorate('json_streamer.write.property_metadata_loader')
|
||||
->args([
|
||||
service('.inner'),
|
||||
])
|
||||
->set('.json_streamer.write.property_metadata_loader.attribute', WriteAttributePropertyMetadataLoader::class)
|
||||
->decorate('json_streamer.write.property_metadata_loader')
|
||||
->args([
|
||||
service('.inner'),
|
||||
tagged_locator('json_streamer.value_transformer'),
|
||||
service('type_info.resolver'),
|
||||
])
|
||||
|
||||
->set('json_streamer.read.property_metadata_loader', PropertyMetadataLoader::class)
|
||||
->args([
|
||||
service('type_info.resolver'),
|
||||
])
|
||||
->set('.json_streamer.read.property_metadata_loader.generic', GenericTypePropertyMetadataLoader::class)
|
||||
->decorate('json_streamer.read.property_metadata_loader')
|
||||
->args([
|
||||
service('.inner'),
|
||||
service('type_info.type_context_factory'),
|
||||
])
|
||||
->set('.json_streamer.read.property_metadata_loader.date_time', ReadDateTimeTypePropertyMetadataLoader::class)
|
||||
->decorate('json_streamer.read.property_metadata_loader')
|
||||
->args([
|
||||
service('.inner'),
|
||||
])
|
||||
->set('.json_streamer.read.property_metadata_loader.attribute', ReadAttributePropertyMetadataLoader::class)
|
||||
->decorate('json_streamer.read.property_metadata_loader')
|
||||
->args([
|
||||
service('.inner'),
|
||||
tagged_locator('json_streamer.value_transformer'),
|
||||
service('type_info.resolver'),
|
||||
])
|
||||
|
||||
// value transformers
|
||||
->set('json_streamer.value_transformer.date_time_to_string', DateTimeToStringValueTransformer::class)
|
||||
->tag('json_streamer.value_transformer')
|
||||
|
||||
->set('json_streamer.value_transformer.string_to_date_time', StringToDateTimeValueTransformer::class)
|
||||
->tag('json_streamer.value_transformer')
|
||||
|
||||
// cache
|
||||
->set('.json_streamer.cache_warmer.streamer', StreamerCacheWarmer::class)
|
||||
->args([
|
||||
abstract_arg('streamable'),
|
||||
service('json_streamer.write.property_metadata_loader'),
|
||||
service('json_streamer.read.property_metadata_loader'),
|
||||
param('.json_streamer.stream_writers_dir'),
|
||||
param('.json_streamer.stream_readers_dir'),
|
||||
service('logger')->ignoreOnInvalid(),
|
||||
])
|
||||
->tag('kernel.cache_warmer')
|
||||
|
||||
->set('.json_streamer.cache_warmer.lazy_ghost', LazyGhostCacheWarmer::class)
|
||||
->args([
|
||||
abstract_arg('streamable class names'),
|
||||
param('.json_streamer.lazy_ghosts_dir'),
|
||||
])
|
||||
->tag('kernel.cache_warmer')
|
||||
;
|
||||
};
|
||||
30
vendor/symfony/framework-bundle/Resources/config/lock.php
vendored
Normal file
30
vendor/symfony/framework-bundle/Resources/config/lock.php
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\Lock\LockFactory;
|
||||
use Symfony\Component\Lock\Store\CombinedStore;
|
||||
use Symfony\Component\Lock\Strategy\ConsensusStrategy;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('lock.store.combined.abstract', CombinedStore::class)->abstract()
|
||||
->args([abstract_arg('List of stores'), service('lock.strategy.majority')])
|
||||
|
||||
->set('lock.strategy.majority', ConsensusStrategy::class)
|
||||
|
||||
->set('lock.factory.abstract', LockFactory::class)->abstract()
|
||||
->args([abstract_arg('Store')])
|
||||
->call('setLogger', [service('logger')->ignoreOnInvalid()])
|
||||
->tag('monolog.logger', ['channel' => 'lock'])
|
||||
;
|
||||
};
|
||||
125
vendor/symfony/framework-bundle/Resources/config/mailer.php
vendored
Normal file
125
vendor/symfony/framework-bundle/Resources/config/mailer.php
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\Mailer\Command\MailerTestCommand;
|
||||
use Symfony\Component\Mailer\EventListener\DkimSignedMessageListener;
|
||||
use Symfony\Component\Mailer\EventListener\EnvelopeListener;
|
||||
use Symfony\Component\Mailer\EventListener\MessageListener;
|
||||
use Symfony\Component\Mailer\EventListener\MessageLoggerListener;
|
||||
use Symfony\Component\Mailer\EventListener\MessengerTransportListener;
|
||||
use Symfony\Component\Mailer\EventListener\SmimeEncryptedMessageListener;
|
||||
use Symfony\Component\Mailer\EventListener\SmimeSignedMessageListener;
|
||||
use Symfony\Component\Mailer\Mailer;
|
||||
use Symfony\Component\Mailer\MailerInterface;
|
||||
use Symfony\Component\Mailer\Messenger\MessageHandler;
|
||||
use Symfony\Component\Mailer\Transport;
|
||||
use Symfony\Component\Mailer\Transport\TransportInterface;
|
||||
use Symfony\Component\Mailer\Transport\Transports;
|
||||
use Symfony\Component\Mime\Crypto\DkimSigner;
|
||||
use Symfony\Component\Mime\Crypto\SMimeSigner;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('mailer.mailer', Mailer::class)
|
||||
->args([
|
||||
service('mailer.transports'),
|
||||
abstract_arg('message bus'),
|
||||
service('event_dispatcher')->ignoreOnInvalid(),
|
||||
])
|
||||
->alias('mailer', 'mailer.mailer')
|
||||
->alias(MailerInterface::class, 'mailer.mailer')
|
||||
|
||||
->set('mailer.transports', Transports::class)
|
||||
->factory([service('mailer.transport_factory'), 'fromStrings'])
|
||||
->args([
|
||||
abstract_arg('transports'),
|
||||
])
|
||||
|
||||
->set('mailer.transport_factory', Transport::class)
|
||||
->args([
|
||||
tagged_iterator('mailer.transport_factory'),
|
||||
])
|
||||
|
||||
->alias('mailer.default_transport', 'mailer.transports')
|
||||
->alias(TransportInterface::class, 'mailer.default_transport')
|
||||
|
||||
->set('mailer.messenger.message_handler', MessageHandler::class)
|
||||
->args([
|
||||
service('mailer.transports'),
|
||||
])
|
||||
->tag('messenger.message_handler')
|
||||
|
||||
->set('mailer.envelope_listener', EnvelopeListener::class)
|
||||
->args([
|
||||
abstract_arg('sender'),
|
||||
abstract_arg('recipients'),
|
||||
])
|
||||
->tag('kernel.event_subscriber')
|
||||
|
||||
->set('mailer.message_listener', MessageListener::class)
|
||||
->args([
|
||||
abstract_arg('headers'),
|
||||
])
|
||||
->tag('kernel.event_subscriber')
|
||||
|
||||
->set('mailer.message_logger_listener', MessageLoggerListener::class)
|
||||
->tag('kernel.event_subscriber')
|
||||
->tag('kernel.reset', ['method' => 'reset'])
|
||||
|
||||
->set('mailer.messenger_transport_listener', MessengerTransportListener::class)
|
||||
->tag('kernel.event_subscriber')
|
||||
|
||||
->set('mailer.dkim_signer', DkimSigner::class)
|
||||
->args([
|
||||
abstract_arg('key'),
|
||||
abstract_arg('domain'),
|
||||
abstract_arg('select'),
|
||||
abstract_arg('options'),
|
||||
abstract_arg('passphrase'),
|
||||
])
|
||||
|
||||
->set('mailer.smime_signer', SMimeSigner::class)
|
||||
->args([
|
||||
abstract_arg('certificate'),
|
||||
abstract_arg('key'),
|
||||
abstract_arg('passphrase'),
|
||||
abstract_arg('extraCertificates'),
|
||||
abstract_arg('signOptions'),
|
||||
])
|
||||
|
||||
->set('mailer.dkim_signer.listener', DkimSignedMessageListener::class)
|
||||
->args([
|
||||
service('mailer.dkim_signer'),
|
||||
])
|
||||
->tag('kernel.event_subscriber')
|
||||
|
||||
->set('mailer.smime_signer.listener', SmimeSignedMessageListener::class)
|
||||
->args([
|
||||
service('mailer.smime_signer'),
|
||||
])
|
||||
->tag('kernel.event_subscriber')
|
||||
|
||||
->set('mailer.smime_encrypter.listener', SmimeEncryptedMessageListener::class)
|
||||
->args([
|
||||
service('mailer.smime_encrypter.repository'),
|
||||
param('mailer.smime_encrypter.cipher'),
|
||||
])
|
||||
->tag('kernel.event_subscriber')
|
||||
|
||||
->set('console.command.mailer_test', MailerTestCommand::class)
|
||||
->args([
|
||||
service('mailer.transports'),
|
||||
])
|
||||
->tag('console.command')
|
||||
;
|
||||
};
|
||||
27
vendor/symfony/framework-bundle/Resources/config/mailer_debug.php
vendored
Normal file
27
vendor/symfony/framework-bundle/Resources/config/mailer_debug.php
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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\DependencyInjection\Loader\Configurator;
|
||||
|
||||
use Symfony\Component\Mailer\DataCollector\MessageDataCollector;
|
||||
|
||||
return static function (ContainerConfigurator $container) {
|
||||
$container->services()
|
||||
->set('mailer.data_collector', MessageDataCollector::class)
|
||||
->args([
|
||||
service('mailer.message_logger_listener'),
|
||||
])
|
||||
->tag('data_collector', [
|
||||
'template' => '@WebProfiler/Collector/mailer.html.twig',
|
||||
'id' => 'mailer',
|
||||
])
|
||||
;
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user