Definice
Jak jste si určitě všimli v úvodních příkladech, tak Jet\Configu využívá atributy (PHP 8) pro které má Jet svou malou nadstavbu Jet\Attributes.
Patřičné atributy musí mít jak třída, která definici konfigurace reprezentuje, tak její vlastnosti, které reprezentují již jednotlivé konfigurační hodnoty.
(Třída pochopitelně může mít pro své interní účely i další vlastnosti zcela bez definic)
Přehled atributů definic si ukážeme dále.
Definice třídy
Definice třídy má aktuálně jediný parametr a tím je název konfigurace - parametr name. Pomocí tohoto parametru se určuje název definované konfigurace a slouží zejména pro ukládání.
Tedy každá třída reprezentující konfiguraci musí určovat název oné konfigurace a musí začínat například takto:
namespace Jet;
#[Config_Definition(name: 'db')]
class Db_Config extends Config
{
//... ... ...
}
Definice vlastnosti - konfigurační hodnoty
Zde už je situace o dost zajímavější :-)
Ty vlastnosti třídy které mají konfigurační definici jsou brány jako konfigurační hodnoty. Platí, že název vlastnosti třídy = název konfigurační hodnoty a pod stejným názvem (nebo v tomto kontextu lépe řečeno klíčem) bude hodnota ukládána do konfiguračního souboru.
Ovšem aby byla definice k něčemu opravdu užitečná, tak je třeba znát mnohem víc informací než je název konfigurační hodnoty / kliče.
Ukažme si opět reálný příklad definice vlastnosti / konfigurační hodnoty, který je přímo z knihovny Jet:
namespace Jet;
#[Config_Definition(name: 'db')]
class Db_Config extends Config
{
#[Config_Definition(
type: Config::TYPE_STRING,
is_required: true,
)]
#[Form_Definition(
type: Form::TYPE_SELECT,
is_required: true,
label: 'Default connection:',
help_text: 'Connection name - default value for Db::get()',
select_options_creator: [
Db_Config::class,
'getConnectionsList'
],
error_messages: [
Form_Field::ERROR_CODE_EMPTY => 'Please select default connection',
Form_Field::ERROR_CODE_INVALID_VALUE => 'Please select default connection'
]
)]
protected string $default_connection_name = 'default';
public function getDefaultConnectionName(): string
{
return $this->default_connection_name;
}
public function setDefaultConnectionName( string $default_connection_name ): void
{
$this->default_connection_name = $default_connection_name;
}
//... ... ...
}
Jak vidíte, tak vlastnost má getter a setter (což je dobrý zvyk, který vřele doporučuji - na velkých a dlouhodobých projektech se to vždy vyplatí) a především více atributů. Pojďme se na ně kouknout.
Základní atributy
Atribut | Význam |
---|---|
type | Typ hodnoty. Typ může být:
|
is_required | Indikuje zda je definice dané hodnoty povinná. Tedy zda v konfiguraci musí být daná hodnota / klíč. |
Specifické atributy
Dále si ukážeme atributy vázané na určité typy konfiguračních hodnot.
Config::TYPE_STRING
Atribut | Význam |
---|---|
validation_regexp | Textová hodnota může být případně validována pomocí regulárního výrazu pomocí kterého je konfigurační hodnota kontrolována. |
Config::TYPE_INT a Config::TYPE_FLOAT
Atribut | Význam |
---|---|
min_value | Číselná hodnota může mít definovanou a ověřovanou minimální hodnotu |
max_value | Číselná hodnota může mít definovanou a ověřovanou maximální hodnotu |
Config::TYPE_SECTION a Config::TYPE_SECTIONS
Atribut | Význam |
---|---|
section_creator_method_name | Název tovární metody pro vytváření definic podsekcí konfigurace. Ovšem toto je samostatné tém - viz dále |
Atributy Form_Definition(*)
Jistě jste si v příkladech všimli atributů Form_Definition. Toto přímo nesouvisí s konfigurací. V Jet můžete takto definovat formulář vlastně na jakékoliv třídě díky mapování tříd na formuláře. Je to univerzální systém, se kterým konfigurace automaticky počítá, ale který je obecně použitelný.
Podsekce konfigurace
O toto téma jsme již lehce zavadili v souvislosti s typy Config::TYPE_SECTION a Config::TYPE_SECTIONS. Nyní si to vysvětlíme podrobněji.
Konfigurace zdaleka není pouze jednoduchá struktura typu klíč -> hodnota. Často potřebujeme podsekce, seznamy podsekcí a to ať už důvodu přehlednosti, tak zejména z důvodů praktických. Ukažme si to opět rovnou na reálném příkladu.
Tím typickým příkladem přímo z "vnitřností" Jet může být konfigurace připojení k databázi Jet\Db.
Tentokrát si pro názornost neukážeme hned třídy, ale příklad již uložené konfigurace:
return [
'default_connection_name' => 'default',
'connections' => [
'default' => [
'driver' => 'mysql',
'name' => 'default',
'host' => 'localhost',
'port' => 3306,
'dbname' => 'our_db',
'charset' => 'utf8',
'username' => '*******',
'password' => '*******',
],
'erp' => [
'driver' => 'oci',
'dsn' => 'dbname=//111.222.111.222:1521/erp_db',
'username' => '*******',
'password' => '*******',
],
'some_small_db' => [
'driver' => 'sqlite',
'name' => 'default',
'path' => '/*****************************/application/data/db.sq3',
],
],
];
Jak je zřejmé, tak spojení na relační databáze může existovat víc než jedno.
A také je patrné, že každé spojení má přesně danou sadu konfiguračních hodnot, která musí být definována, ale zároveň každý typ spojení může mít jinou podobu dle typu databáze.
Jak toho docílit si ukážeme za chvíli. Nejprve se vraťme je třídě Jet\Db_Config, jejíž část jsme si ukazovali v této kapitole.
Předchozí ukázka konfigurační třídy Jet\Db_Config byla pouze o parametru / klíči 'default_connection_name'.
Nyní si ukažme tu část, která řeší 'connections':
#[Config_Definition(name: 'db')]
class Db_Config extends Config
{
#[Config_Definition(
type: Config::TYPE_SECTIONS,
section_creator_method_name: 'connectionConfigCreator'
)]
protected ?array $connections = null;
public function connectionConfigCreator( array $data ): Db_Backend_Config
{
return Factory_Db::getBackendConfigInstance( $data );
}
/**
* @return Db_Backend_Config[]
*/
public function getConnections(): array
{
return $this->connections;
}
public function getConnection( string $connection_name ): Db_Backend_Config|null
{
if( !isset( $this->connections[$connection_name] ) ) {
return null;
}
return $this->connections[$connection_name];
}
public function addConnection( string $connection_name, Db_Backend_Config $connection_configuration ): void
{
$this->connections[$connection_name] = $connection_configuration;
}
public function deleteConnection( string $connection_name ): void
{
if( isset( $this->connections[$connection_name] ) ) {
unset( $this->connections[$connection_name] );
}
}
}
Jak vidíte, tak třída má vlastnost $connections a ta je definována jako typ Config::TYPE_SECTIONS.
Zároveň je pomocí atributu section_creator_method_name definován název tovární metody. Tovární metoda se stará o to, aby se ze surových dat v podobě načteného asociovaného pole stala definice spojení - tedy instance určité příslušné třídy, která představuje definici konkrétní části konfigurace (zde konkrétního spojení).
Definici části konfigurace v tomto případě představuje třída Jet\Db_Backend_Config (respektive ve skutečnosti o třídu Jet\Db_Backend_PDO_Config, ale teď to nekomplikujme :-) ).
Určitě vaší pozornosti neušlo použití továrny ( Factory_Db::getBackendConfigInstance( $data )) - tedy třída je zaměnitelná, ale to nesouvisí s tématem konfigurace a její definice. Zpět k tématu :-)
Shrňme si to - pokud budete chtít mít v konfiguraci podsekci, nebo podsekce, tak potřebujete:
- V definici konfigurace mýt vlastnost (vlastnosti) typu Config::TYPE_SECTION (pokud má jít o prostou podsekci), nebo Config::TYPE_SECTIONS (pokud má jít o seznam jako v tomto případě).
- Potřebujete mít definiční třídu pro danou sekci / sekce. V tomto případě tedy Db_Backend_Config, která již definuje konfiguraci konkrétního připojení na databázi.
- V hlavní třídě definující konfiguraci je určit vhodné mít další metody pro manipulaci se sekcemi. Jako například v tomto příkladu pro přidávání a odebírání spojení a tak dále.
Definice sekce konfigurace pak může mít například tuto podobu:
#[Config_Definition]
abstract class Db_Backend_Config extends Config_Section
{
#[Config_Definition(
type: Config::TYPE_STRING,
is_required: true,
)]
#[Form_Definition(
type: Form::TYPE_SELECT,
label: 'Driver',
help_text: 'PDO driver',
is_required: true,
select_options_creator: [
self::class,
'getDrivers'
],
error_messages: [
Form_Field::ERROR_CODE_EMPTY => 'Please select driver',
Form_Field::ERROR_CODE_INVALID_VALUE => 'Please select driver'
]
)]
protected string $driver = 'mysql';
#[Config_Definition(
type: Config::TYPE_STRING,
is_required: true,
)]
#[Form_Definition(
type: Form_Field::TYPE_INPUT,
label: 'Connection name',
is_required: true,
error_messages: [
Form_Field::ERROR_CODE_EMPTY => 'Please enter connection name'
]
)]
protected string $name = 'default';
//... ... ...
//... ... ...
//... ... ...
}
Jak vidíte, tak definice sekce konfigurace je téměř stejná, jako hlavní definice konfigurace. Jsou pouze dva drobné, ale zásadní rozdíly:
- Třída nedědí od Jet\Config, ale od Jet\Config_Section
- Třída sama nemá žádné hodnoty atributů. Potřebné jsou pouze definice vlastností.
Jednoduše se dá říct, že jedna konfigurace zapadá do druhé. A ano, podsekce může mít další podsekce.
Nyní již víte jak funguje definice konfigurace a jak se s tím pracuje z pohledu aplikace. Dále doporučuji kouknout na třídu Jet\Config, které je ústředním bodem celého subsystému.