Skip to content

Commit 4c40c32

Browse files
authored
Merge pull request #279 from WebFiori/feat-env-vars
feat: Environment Variables Reslotion
2 parents 95acf48 + a8ee667 commit 4c40c32

10 files changed

Lines changed: 560 additions & 27 deletions

File tree

App/Config/config-with-env.json

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"base-url":"DYNAMIC",
3+
"theme":null,
4+
"home-page":"BASE_URL",
5+
"primary-lang":"env:LANG",
6+
"titles":{
7+
"AR":"افتراضي",
8+
"EN":"Default"
9+
},
10+
"name-separator":"|",
11+
"scheduler-password":"env:SCHEDULER_PASS",
12+
"app-names":{
13+
"AR":"تطبيق",
14+
"EN":"Application"
15+
},
16+
"app-descriptions":{
17+
"AR":"",
18+
"EN":""
19+
},
20+
"version-info":{
21+
"version":"1.0",
22+
"version-type":"Stable",
23+
"release-date":"2023-10-30"
24+
},
25+
"env-vars":{
26+
"WF_VERBOSE_2":{
27+
"value":"env:VERBOSE",
28+
"description":"Configure the verbosity of error messsages at run-time. This should be set to true in testing and false in production."
29+
},
30+
"CLI_HTTP_HOST_2":{
31+
"value":"example.com",
32+
"description":"Host name that will be used when runing the application as command line utility."
33+
},
34+
"HOST":"env:HOST"
35+
},
36+
"smtp-connections":{
37+
"conn00": {
38+
"host":"smtp.outlook.com",
39+
"port":"244",
40+
"username":"env:SMTP_00_USER",
41+
"password":"env:SMTP_00_PASS",
42+
"address":"env:SMTP_00_ADDRESS",
43+
"sender-name":"env:SMTP_00_NAME",
44+
"access-token":"env:SMTP_TOKEN"
45+
}
46+
},
47+
"database-connections":{
48+
"New_Connection":{
49+
"type":"mysql",
50+
"host":"env:DB_HOST_1",
51+
"port":3306,
52+
"username":"cool",
53+
"database":"env:DB_NAME_1",
54+
"password":"env:DB_PASS_1",
55+
"extras":{
56+
}
57+
},
58+
"New_Connection_2":{
59+
"type":"mysql",
60+
"host":"env:DB_HOST_2",
61+
"port":3306,
62+
"database":"env:DB_NAME_2",
63+
"password":"env:DB_PASS_2",
64+
"username":"cool",
65+
"extras":{
66+
}
67+
}
68+
}
69+
}

CHANGELOG.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,70 @@
11
# Changelog
22

3+
## [3.0.0-beta.31](https://github.com/WebFiori/framework/compare/v3.0.0-Beta.30...v3.0.0-beta.31) (2025-10-27)
4+
5+
6+
### Bug Fixes
7+
8+
* Bug in Finding Class Loader Path ([6831a96](https://github.com/WebFiori/framework/commit/6831a96d91962480b097561b559e2ecf07af1c0b))
9+
* Show Framework Logo ([e47f1a5](https://github.com/WebFiori/framework/commit/e47f1a5d70b5d5982ff87247de3feb98ce75d558))
10+
11+
12+
### Miscellaneous Chores
13+
14+
* Merge pull request [#271](https://github.com/WebFiori/framework/issues/271) from WebFiori/dev ([6bf9c26](https://github.com/WebFiori/framework/commit/6bf9c26ab448e60bcdfee5f6f91b2cdc97304006))
15+
* Updated Framework Version ([3d719ea](https://github.com/WebFiori/framework/commit/3d719ea32aea00d973dbb61e5ddf98194a5e7e0f))
16+
* Updated Index ([0b128ec](https://github.com/WebFiori/framework/commit/0b128ec53339304b351df9d1953e192dc233a24a))
17+
18+
## [3.0.0-Beta.30](https://github.com/WebFiori/framework/compare/v3.0.0-Beta.29...v3.0.0-Beta.30) (2025-10-21)
19+
20+
21+
### Features
22+
23+
* Added a Script to Update Version ([e998c47](https://github.com/WebFiori/framework/commit/e998c476b2629b6b8307d6ad52813cdc1a63eb05))
24+
25+
26+
### Bug Fixes
27+
28+
* Metadata ([84facc3](https://github.com/WebFiori/framework/commit/84facc3638ce6989d9b3efcf6dc05f9b7f87944b))
29+
30+
31+
### Miscellaneous Chores
32+
33+
* Merge pull request [#269](https://github.com/WebFiori/framework/issues/269) from WebFiori/dev ([8ffb523](https://github.com/WebFiori/framework/commit/8ffb523559ab609095da446b2d592607dac1f20e))
34+
35+
## [3.0.0-Beta.29](https://github.com/WebFiori/framework/compare/v3.0.0-Beta.28...v3.0.0-Beta.29) (2025-10-09)
36+
37+
38+
### Bug Fixes
39+
40+
* API Creation ([d3c384f](https://github.com/WebFiori/framework/commit/d3c384f48f61c828cf9358cbb1675e26be25b0ee))
41+
* Command Writer ([338e8d2](https://github.com/WebFiori/framework/commit/338e8d2d7e72e66463bb8d57a6b34f20aa38ff3b))
42+
* Fix Test Case ([6b26e2f](https://github.com/WebFiori/framework/commit/6b26e2f023cea94eb7fdf2a665f1a721e5e190eb))
43+
* Fix Test Cases ([1086336](https://github.com/WebFiori/framework/commit/108633622e1938699360b45d65d3565bcf611e85))
44+
* Fix Test Cases ([0c914de](https://github.com/WebFiori/framework/commit/0c914de97f37eef1bf862c4b37f323470dfcf5ef))
45+
* Fixes and Tests Refactoring ([5ff31ab](https://github.com/WebFiori/framework/commit/5ff31ab5dc2c33b8a9389f3bf33001a525f57a7d))
46+
* Getting Arg Value in CLI ([c56b9bf](https://github.com/WebFiori/framework/commit/c56b9bf6f34617336ad1f750943f705d84357ba0))
47+
* Migrations Command ([ce54748](https://github.com/WebFiori/framework/commit/ce5474803a26352b75eaea66604b630378b98aa9))
48+
* Namespaces ([e51d354](https://github.com/WebFiori/framework/commit/e51d354a2be0843f55e70ced529c45341988ba2e))
49+
* References to Classes ([a140646](https://github.com/WebFiori/framework/commit/a1406462197a32a8bd16a6d12168c8c2a4fda016))
50+
* Tasks Names Check ([3c80893](https://github.com/WebFiori/framework/commit/3c80893d4c793e330f571205a702b853540d9a36))
51+
* Test Cases ([f78c6d5](https://github.com/WebFiori/framework/commit/f78c6d5a2b9fa10baa98ce9c229295d95f5b0fef))
52+
* Test Classes ([cd68b49](https://github.com/WebFiori/framework/commit/cd68b49acbc7dab3d8abc25fa3df21b129d19bf4))
53+
* Theme Creation ([6864c23](https://github.com/WebFiori/framework/commit/6864c236e7174113a4b4dc26e8289ed2645bb278))
54+
* Theme Resources Creation ([e9f1025](https://github.com/WebFiori/framework/commit/e9f10258f4433982e922cac494dec69b06f34e8b))
55+
* Writing Classes ([2fcb0c5](https://github.com/WebFiori/framework/commit/2fcb0c5993d7eb47c270d8113f58a2cf13f76046))
56+
57+
58+
### Miscellaneous Chores
59+
60+
* Merge pull request [#266](https://github.com/WebFiori/framework/issues/266) from WebFiori/dev ([19fc94a](https://github.com/WebFiori/framework/commit/19fc94a9166ecafb2572e0926f9992b93a170341))
61+
* Merge pull request [#268](https://github.com/WebFiori/framework/issues/268) from WebFiori/dev ([fb1e6a3](https://github.com/WebFiori/framework/commit/fb1e6a3bb3d5b69642641fd323e82785f28c72f9))
62+
* Updated Database Library ([7f853fd](https://github.com/WebFiori/framework/commit/7f853fd25fd9f0b1211fb18fc807a2436f403946))
63+
* Updated Database to v1.0.0 ([c35b109](https://github.com/WebFiori/framework/commit/c35b109d292df38b32965ceed0bd7e0a90c8cc08))
64+
* Updated Dependencies ([ff05d95](https://github.com/WebFiori/framework/commit/ff05d95b8923ee631649c4610bf7dd348dcd4869))
65+
* Updated HTTP to v4 ([ab525fc](https://github.com/WebFiori/framework/commit/ab525fc9a37db07ae454b53e961cddba628b82e3))
66+
* Updated Version Number ([c2bac79](https://github.com/WebFiori/framework/commit/c2bac791aa6aca1bd9e8742c017d75e8574fd38d))
67+
368
## [3.0.0-Beta.26](https://github.com/WebFiori/framework/compare/v3.0.0-Beta.26...v3.0.0-Beta.26) (2025-04-07)
469

570

WebFiori/Framework/App.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,7 @@ private static function getRoot() {
726726
* @throws Exception
727727
*/
728728
private static function initAutoLoader() {
729+
Ini::createAppDirs();
729730
/**
730731
* Initialize autoloader.
731732
*/
@@ -744,7 +745,6 @@ private static function initAutoLoader() {
744745
}
745746

746747
if (!class_exists(APP_DIR.'\\Ini\\AutoLoad')) {
747-
Ini::createAppDirs();
748748
Ini::get()->createIniClass('AutoLoad', 'Add user-defined directories to the set of directories at which the framework will search for classes.');
749749
}
750750
self::call(APP_DIR.'\\Ini\\AutoLoad::initialize');

WebFiori/Framework/Config/ClassDriver.php

Lines changed: 106 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@
1515
* create a class called 'AppConfig' on the directory APP_DIR/Config and
1616
* use it to read and write configurations.
1717
*
18+
* ## Environment Variable Support
19+
*
20+
* This driver supports environment variable substitution using the 'env:' prefix.
21+
* The following configuration sections support this feature:
22+
* - Database connections (all properties)
23+
* - SMTP connections (all properties)
24+
* - Environment variables (value field)
25+
* - Scheduler password
26+
*
27+
* Values stored in the generated PHP class can use the 'env:' prefix, and they
28+
* will be resolved to their environment variable values when read.
29+
*
1830
* @author Ibrahim
1931
*/
2032
class ClassDriver implements ConfigurationDriver {
@@ -60,6 +72,9 @@ public static function a($file, $str, $tabSize = 0) {
6072
* a named constant at run time using the function 'define'. This means
6173
* the constant will be accesaable anywhere within the appllication's environment.
6274
*
75+
* Note: The value parameter supports the 'env:' prefix for referencing
76+
* system environment variables (e.g., "env:MY_VAR").
77+
*
6378
* @param string $name The name of the named constant such as 'MY_CONSTANT'.
6479
*
6580
* @param mixed $value The value of the constant.
@@ -77,6 +92,10 @@ public function addEnvVar(string $name, mixed $value = null, ?string $descriptio
7792
/**
7893
* Adds new database connections information or update existing connection.
7994
*
95+
* Note: When using this driver, connection properties support environment variable
96+
* substitution using the 'env:' prefix. Values will be stored in the generated PHP class
97+
* and resolved when read.
98+
*
8099
* @param ConnectionInfo $dbConnectionsInfo An object which holds connection information.
81100
*/
82101
public function addOrUpdateDBConnection(ConnectionInfo $dbConnectionsInfo) {
@@ -86,6 +105,10 @@ public function addOrUpdateDBConnection(ConnectionInfo $dbConnectionsInfo) {
86105
/**
87106
* Adds new SMTP account or Updates an existing one.
88107
*
108+
* Note: When using this driver, SMTP account properties support environment variable
109+
* substitution using the 'env:' prefix. Values will be stored in the generated PHP class
110+
* and resolved when read.
111+
*
89112
* @param SMTPAccount $emailAccount An instance of 'SMTPAccount'.
90113
*/
91114
public function addOrUpdateSMTPAccount(SMTPAccount $emailAccount) {
@@ -157,6 +180,9 @@ public function getBaseURL(): string {
157180
/**
158181
* Returns database connection information given connection name.
159182
*
183+
* Note: Connection properties that use the 'env:' prefix will be
184+
* automatically resolved to their environment variable values.
185+
*
160186
* @param string $conName The name of the connection.
161187
*
162188
* @return ConnectionInfo|null The method will return an object of type
@@ -174,10 +200,30 @@ public function getDBConnection(string $conName) {
174200
/**
175201
* Returns an associative array that contain the information of database connections.
176202
*
203+
* Note: Connection properties that use the 'env:' prefix will be
204+
* automatically resolved to their environment variable values.
205+
*
177206
* @return array An associative array of objects of type ConnectionInfo.
178207
*/
179208
public function getDBConnections(): array {
180-
return $this->configVars['database-connections'];
209+
$connections = $this->configVars['database-connections'];
210+
211+
foreach ($connections as $name => $connObj) {
212+
if ($connObj instanceof ConnectionInfo) {
213+
$connObj->setHost(Controller::resolveEnvValue($connObj->getHost()));
214+
$connObj->setUsername(Controller::resolveEnvValue($connObj->getUsername()));
215+
$connObj->setPassword(Controller::resolveEnvValue($connObj->getPassword()));
216+
$connObj->setDBName(Controller::resolveEnvValue($connObj->getDBName()));
217+
218+
$extras = $connObj->getExtars();
219+
foreach ($extras as $key => $value) {
220+
$extras[$key] = Controller::resolveEnvValue($value);
221+
}
222+
$connObj->setExtras($extras);
223+
}
224+
}
225+
226+
return $connections;
181227
}
182228

183229
public function getDescription(string $langCode) {
@@ -198,12 +244,25 @@ public function getDescriptions(): array {
198244
/**
199245
* Returns an associative array of application constants.
200246
*
247+
* Note: Environment variable values that use the 'env:' prefix will be
248+
* automatically resolved to their system environment variable values.
249+
*
201250
* @return array The indices of the array are names of the constants and
202251
* values are sub-associative arrays. Each sub-array will have two indices,
203252
* 'value' and 'description'.
204253
*/
205254
public function getEnvVars(): array {
206-
return $this->configVars['env-vars'];
255+
$vars = $this->configVars['env-vars'];
256+
257+
foreach ($vars as $name => $varData) {
258+
if (is_array($varData) && isset($varData['value'])) {
259+
$vars[$name]['value'] = Controller::resolveEnvValue($varData['value']);
260+
} else {
261+
$vars[$name] = Controller::resolveEnvValue($varData);
262+
}
263+
}
264+
265+
return $vars;
207266
}
208267
/**
209268
* Returns a string that represents the URL of home page of the application.
@@ -221,9 +280,17 @@ public function getHomePage() : string {
221280
public function getPrimaryLanguage() : string {
222281
return $this->configVars['site']['primary-lang'];
223282
}
224-
283+
/**
284+
* Returns sha256 hash of the password which is used to prevent unauthorized
285+
* access to run the tasks or access scheduler web interface.
286+
*
287+
* Note: The scheduler password value supports environment variable substitution
288+
* using the 'env:' prefix (e.g., "env:SCHEDULER_PASS").
289+
*
290+
* @return string Password hash or the string 'NO_PASSWORD' if there is no password.
291+
*/
225292
public function getSchedulerPassword(): string {
226-
return $this->configVars['scheduler-password'];
293+
return Controller::resolveEnvValue($this->configVars['scheduler-password']);
227294
}
228295

229296
public function getSMTPAccount(string $name) {
@@ -242,15 +309,48 @@ public function getSMTPAccount(string $name) {
242309
* will return an object of type SMTPAccount. Else, the
243310
* method will return null.
244311
*
312+
*/ /**
313+
* Returns SMTP connection given its name.
314+
*
315+
* Note: SMTP account properties that use the 'env:' prefix will be
316+
* automatically resolved to their environment variable values.
317+
*
318+
* @param string $name The name of the account.
319+
*
320+
* @return SMTPAccount|null If the account is found, The method
321+
* will return an object of type SMTPAccount. Else, the
322+
* method will return null.
323+
*
245324
*/
246325
public function getSMTPConnection(string $name) {
247326
if (isset($this->getSMTPConnections()[$name])) {
248327
return $this->getSMTPConnections()[$name];
249328
}
250329
}
251-
330+
/**
331+
* Returns an array that contains all added SMTP accounts.
332+
*
333+
* Note: SMTP account properties that use the 'env:' prefix will be
334+
* automatically resolved to their environment variable values.
335+
*
336+
* @return array An associative array of SMTPAccount objects.
337+
*/
252338
public function getSMTPConnections(): array {
253-
return $this->configVars['smtp-connections'];
339+
$connections = $this->configVars['smtp-connections'];
340+
341+
foreach ($connections as $name => $smtpObj) {
342+
if ($smtpObj instanceof SMTPAccount) {
343+
$smtpObj->setServerAddress(Controller::resolveEnvValue($smtpObj->getServerAddress()));
344+
$smtpObj->setPort(Controller::resolveEnvValue($smtpObj->getPort()));
345+
$smtpObj->setUsername(Controller::resolveEnvValue($smtpObj->getUsername()));
346+
$smtpObj->setPassword(Controller::resolveEnvValue($smtpObj->getPassword()));
347+
$smtpObj->setAddress(Controller::resolveEnvValue($smtpObj->getAddress()));
348+
$smtpObj->setSenderName(Controller::resolveEnvValue($smtpObj->getSenderName()));
349+
$smtpObj->setAccessToken(Controller::resolveEnvValue($smtpObj->getAccessToken()));
350+
}
351+
}
352+
353+
return $connections;
254354
}
255355

256356
public function getTheme(): string {

0 commit comments

Comments
 (0)