이 시리즈의 처음 두 부분에서는 설정 번들의 기본 개념과 이를 사용하여 Symfony 애플리케이션에서 사용자가 구성할 수 있는 멋진 설정을 만드는 방법을 소개했습니다.
이 부분에서는 설정에 버전을 지정하고 설정 간에 마이그레이션하는 방법을 알아봅니다. 또한 환경 변수를 설정과 결합하는 방법을 배우게 됩니다.
시간이 지남에 따라 애플리케이션이 발전하고 설정도 발전할 것입니다. 이는 시간이 지남에 따라 새로운 매개변수가 설정에 추가되고, 이전 매개변수는 제거되고, 기존 매개변수는 변경된다는 것을 의미합니다. 이를 처리하기 위해 설정 번들은 대부분의 작업을 처리하는 버전 관리 및 마이그레이션 메커니즘을 제공합니다.
다음과 같은 간단한 설정 클래스가 있다고 가정해 보겠습니다.
namespace App\Settings; use Jbtronics\SettingsBundle\Settings\Settings; use Jbtronics\SettingsBundle\Settings\SettingsParameter; #[Settings] class TestSettings { #[SettingsParameter] public string $email = 'test@invalid'; #[SettingsParameter] public int $baz = 42; }
이러한 설정은 이미 애플리케이션에서 한동안 사용되었으며 사용자는 이미 사용자 정의 내용을 저장했습니다. 설정에 새 매개변수만 추가하려는 경우 클래스에 새 속성을 추가하기만 하면 문제 없이 작동합니다. 새 매개변수는 기본값으로 초기화되며 사용자는 원하는 대로 이를 변경할 수 있습니다.
#[Settings] class TestSettings { #[SettingsParameter] public string $email = 'test@invalid'; #[SettingsParameter] public int $baz = 42; #[SettingsParameter] public bool $qux = true; }
매개변수 제거도 비슷하게 작동합니다. 클래스에서 속성을 제거하면 설정 번들은 해당 속성의 기존 값을 무시하고 다음에 설정을 저장할 때 삭제합니다.
그러나 더 까다로운 것은 필드 이름을 바꾸거나 더 복잡하게는 필드 유형이나 데이터가 정확히 저장되는 방식을 변경하려는 경우입니다. 사용자의 기존 사용자 정의 내용을 잃지 않으려면 설정의 다양한 표현 간에 변환하는 방법을 지정해야 합니다. 설정 번들은 마이그레이션 프레임워크를 제공하여 이를 지원할 수 있습니다.
이제 여러 이메일 주소를 가질 수 있는 방식으로 설정 클래스를 변경한다고 가정해 보겠습니다. 또한 baz 매개변수의 인덱싱을 변경하여 0에서 시작하지 않고 1에서 시작하도록 하려고 합니다. 즉, 모든 기존 값이 1씩 증가해야 합니다. 결국 설정 클래스는 다음과 같아야 합니다.
namespace App\Settings; use Jbtronics\SettingsBundle\Settings\Settings; use Jbtronics\SettingsBundle\Settings\SettingsParameter; #[Settings(version: self::VERSION, migrationService: TestSettingsMigration::class)] class TestSettings { public const VERSION = 1; #[SettingsParameter(type: ArrayType::class, options: ['type' => StringType::class])] public array $email = ['test@invalid']; #[SettingsParameter] //Now with different indexing public int $baz = 43; }
이제 테스트 설정 클래스는 새로운 의도된 구조를 가지며 애플리케이션에서 사용할 수 있습니다. 그러나 설정 번들은 기존 데이터를 새 구조로 변환하는 방법을 모릅니다. 마이그레이션이 이루어지는 곳입니다
놀러오세요.
이제 설정 속성에 버전 옵션과 migrationService 옵션이 지정된 것을 확인할 수 있습니다.
버전 옵션은 설정의 최신 스키마 버전을 지정하며 설정 클래스의 구조를 변경할 때마다 증가하는 정수(0보다 큰 값)입니다. 1부터 시작하여 설정 클래스의 구조를 변경할 때마다 증가시킬 수 있습니다. 버전 번호를 속성에 직접 입력하거나 예제와 같이 상수를 정의할 수 있습니다. 이는 클래스 외부에서 쉽게 현재 버전을 검색할 수 있다는 장점이 있습니다.
두 번째로 새로워진 점은 migrationService 옵션입니다. 실제로 데이터 마이그레이션을 수행하는 서비스 클래스를 지정합니다. migrationService는 지정된 두 버전의 데이터 간에 마이그레이션을 수행하는 마이그레이션 기능을 지정하는 SettingsMigrationInterface를 구현해야 합니다.
대부분의 경우 버전 간 단계적 마이그레이션을 원합니다. 즉, 코드 중복을 피하기 위해 1 -> 3을 직접 마이그레이션하는 대신 1 -> 2, 2 -> 3 등을 마이그레이션합니다. 이 상황에서는 SettingsMigration 클래스를 확장하는 것이 더 쉽습니다. 이 추상 클래스를 사용하면 마이그레이션 서비스는 다음과 같을 수 있습니다.
namespace App\Settings\Migrations; use Jbtronics\SettingsBundle\Migrations\SettingsMigration; class TestSettingsMigration extends SettingsMigration { /** * This method is called automatically by the migration class and handles * migration of version 0 (non versioned settings) to version 1. */ public function migrateToVersion1(array $data, SettingsMetadata $metadata): array { /* * $data contains the old settings data, in the normalized form (in the way it was saved in the database) * Each key is the parameter name (not necessarily the property name) * * In the end we must return the new data in the normalized form, which is later then passed to * the parameter type converters. */ //If the email parameter was set, convert it to an array if (isset($data['email'])) { $data['email'] = [$data['email']]; } //Increment the baz parameter, if it was set if (isset($data['baz'])) { $data['baz']++; } //Return the new data return $data; } /** * This method is called, to handle migration from version 1 to version 2. */ public function migrateToVersion2(array $data, SettingsMetadata $metadata): array { //Perform some more migrations... return $data; } }
마이그레이션 서비스에는 설정이 버전 XX-1에서 버전 XX로 마이그레이션되는 경우 클래스에서 자동으로 호출되는 migrationToVersionXX() 형식의 다양한 메서드가 포함되어 있습니다. 메서드는 정규화된 형식의 데이터와 설정 클래스의 메타데이터를 수신하고 정규화된 형식의 데이터를 반환해야 하며, 이 데이터는 매개변수 유형 변환기에 전달됩니다. 어떤 버전에 대해 어떤 함수가 호출되는지 명시적으로 지정하려면 해당 버전에 사용할 클로저를 반환하는solveStepHandler 메서드를 재정의할 수 있습니다.
기존 데이터에는 아직 버전이 없으므로 버전 0인 것으로 가정합니다. 따라서 이러한 데이터 설정 번들은 migrationToVersion1 핸들러를 호출하여 0에서 최신 버전 1로 마이그레이션합니다.
The old data from the storage is passed to the migration method (as $data) and you have to convert it to the new form how it can be saved to storage and how the parameter type conversions can understand it. Each parameter is stored in the $data array with the parameter name as key. You can then modify the data as you like and return it in the end.
Please note that the $data array is in the normalized form, meaning that you only have simple datatypes like strings, integers, arrays and so on. If you want to like to work with the denormalized form (like objects, etc.) you might find the getAsPHPValue() and setAsPHPValue() methods available in the SettingsClass (or in the PHPValueConverterTrait) useful. Or you call the ParameterTypes you need directly.
The settings-bundle stores the version of the data in the storage provider, so that it is automatically known what version the data has and what migrations to perform. The migrations are automatically performed when trying to retrieve settings data (by getting the settings from the SettingsManager or calling a property of a lazy settings class). By default, the migrated data is written back to the storage after the migration, so that the migration only has to be performed once for each setting, even if the settings are not explicitly written back to the storage.
Environment variables are one of the classic possibilities to configure a Symfony application. They allow you for an easy configuration approach in automatic deployed applications, containers, etc. via a more or less unified interface. So they are pretty ideal for server administrators, who want to configure an application without touching the code. However, the big disadvantage of environment variables is, that they are not user-configurable, as users (even those intended as admin users) can not change them without direct access to the server.
To retain the advantages of environment variables, while also allowing users to configure the applications via the settings-bundle, the bundle can map environment variables to settings class parameters.
This is done via the envVar option on the SettingsParameter attribute:
#[Settings] class TestSettings { #[SettingsParameter(envVar: 'APP_EMAIL')] public string $email = 'test@invalid'; #[SettingsParameter(envVar: 'int:APP_BAZ', envVarMode: EnvVarMode::OVERWRITE)] public int $baz = 42; #[SettingsParameter(envVar: 'bool:APP_TEST_SETTINGS_QUX', envVarMode: EnvVarMode::OVERWRITE_PERSIST)] public bool $qux = true; }
The envVar option specifies the environment variable to map to the parameter. If it does not exist, nothing happens. However, if it exists, the bundle will retrieve the value of the environment variable and set it as the value of the parameter. By default, the "raw" environment variable contains just a string. If you have another simple data type (like an integer or a boolean), you can use one of Symfony's env var processors to convert the string value of the env variable to the desired type (e.g. int:APP_BAZ, which converts the content of APP_BAZ to an int).
The environment variable handling happens transparently in the background, meaning that you can use the settings class as usual, and you (almost) do not have to care about the environment variables when using the settings.
The envVarMode option specifies how the environment variable should be handled. If no mode is specified, the mode EnvVarMode::INITIAL is used. In this mode the environment variable is only used to initialize the parameter. That means if the parameter is used the first time, instead of the default value in the code, the value of the environment variable is used. Users can change this value as they like, and the environment variable will not affect the parameter anymore. This mode allows a server administrator to set useful initial defaults via environment variables (e.g. while deploying the container), but users can change them completely later.
However, in some cases, you might want the server admin to enforce a certain value via environment variables and forbid users to change them via WebUI. For these cases, you can use the EnvVarMode::OVERWRITE and EnvVarMode::OVERWRITE_PERSIST mode. In this mode, the environment variable will always overwrite a parameter value, no matter what was set as a value before by users. This means that freshly retrieved settings will always have the value of the environment variable, even if the user changed it before. The OVERWRITE_PERSIST mode additionally writes the value back to the storage, so that the value is still set even after the env variable is removed (however users can then change the value again).
If a parameter is overwritten by an environment variable, its form field will be disabled in the default generated WebUI, so that users can see that the value is enforced by the environment variable and can not be changed via the WebUI.
A limitation of this system is that you can still change the value of a settings parameter in your code, even if it is overwritten by an environment variable. The changes will also be used in other parts of the application during the request. It is just that these changes do not get persisted, meaning that if you reload the settings from the storage, the value of the environment variable will be used again. If you try to change settings parameters via direct access in you code, you might want to check if the parameter is overwritten by an environment variable (by using the isEnvVarOverwritten method of the SettingsManager), and if so, you might want to disable the possibility to change the parameter in your code.
For many constellations, the type conversion via the env var processor works fine. However, in some cases where you have more complex parameter types, you need a more complex conversion logic. For these cases, you can use the envVarMapper option of the SettingsParameter attribute. This option specifies a callable, which is called with the value of the environment variable and must return the value to set as the parameter value:
class TestSettings { #[SettingsParameter(envVar: 'string:ENV_VAR3', envVarMapper: [self::class, 'mapDateTimeEnv']) private ?\DateTime $dateTimeParam = null; public static function mapDateTimeEnv(?string $value): ?\DateTime { return $value ? new \DateTime($value) : null; } }
The $value parameter passed, is the value retrieved from the environment variable, with env var processors applied, meaning that it not necessarily has to be a string.
You can see that jbtronics/settings-bundle can support you with handling changes in the schema of settings, and how to map environment variables to settings parameters. This allows you to have a flexible configuration system, which can be used by users and server administrators alike.
As always you can find more information in the bundle documentation.
위 내용은 jbtronics/settings-bundle을 사용하여 Symfony 애플리케이션에서 사용자 구성 가능한 설정(부품 마이그레이션 및 환경 변수)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!