folderweb/docs/04-development/03-configuration.md

115 lines
3.9 KiB
Markdown
Raw Permalink Normal View History

# Configuration
## Config Loading
**`createContext()`** in `app/config.php` handles the full bootstrap:
1. Parse `app/default/config.ini` (framework defaults)
2. If `custom/config.ini` exists, merge via `array_replace_recursive` (custom wins)
3. Load global plugins using merged config
4. Determine content directory
5. Create `Context` object
6. Fire `Hook::CONTEXT_READY` — plugins receive the merged `$config` array
## INI Format
Standard PHP `parse_ini_file` with sections enabled:
```ini
[languages]
default = "en"
available = "no,en"
[plugins]
enabled = "languages"
[custom_section]
key = "value"
```
## Built-in Config Keys
| Section | Key | Type | Default | Purpose |
|---|---|---|---|---|
| `languages` | `default` | string | `"en"` | Default language (no URL prefix) |
| `languages` | `available` | string | `"no,en"` | Comma-separated ISO 639-1 codes |
| `plugins` | `enabled` | string | `"languages"` | Comma-separated plugin names (without `.php`) |
All other sections are custom — define whatever your plugins need.
## The custom/ Override System
This is the primary mechanism for using FolderWeb. The `custom/` directory is the user layer:
```
custom/
config.ini # Merged over app/default/config.ini
templates/ # Override by matching filename (e.g., base.php, page.php, list.php)
styles/ # Served at /app/styles/*
fonts/ # Served at /app/fonts/*
assets/ # Served at document root (favicon.ico, robots.txt, etc.)
languages/ # Merged over app/default/languages/*.ini
plugins/
global/ # Loaded alongside app/plugins/global/
page/ # Reserved for future use
```
### Override Resolution Order
| Resource | Lookup | Fallback |
|---|---|---|
| Templates | `custom/templates/{name}.php` | `app/default/templates/{name}.php` |
| Styles | `custom/styles/*` via `/app/styles/*` | `app/default/styles/*` via `/app/default-styles/*` |
| Languages | `custom/languages/{lang}.ini` merged over | `app/default/languages/{lang}.ini` |
| Config | `custom/config.ini` merged over | `app/default/config.ini` |
| Plugins | `custom/plugins/{scope}/{name}.php` | `app/plugins/{scope}/{name}.php` |
For plugins, custom takes priority: if both `custom/plugins/global/foo.php` and `app/plugins/global/foo.php` exist, the custom version loads.
For full template resolution details, see `06-templates.md` "Template Resolution (canonical reference)".
### Static Asset Routing
The router checks these locations before content routing:
1. `custom/assets/{requestPath}` — served with `mime_content_type()`
2. `{contentDir}/{requestPath}` — served with explicit MIME map for: `css`, `jpg`, `jpeg`, `png`, `gif`, `webp`, `svg`, `pdf`, `woff`, `woff2`, `ttf`, `otf`
`/app/*` requests are handled by `static.php`:
- `/app/styles/*``custom/styles/*`
- `/app/fonts/*``custom/fonts/*`
- `/app/assets/*``custom/assets/*`
- `/app/default-styles/*``app/default/styles/*`
## Accessing Config in Plugins
The merged config array is passed to `Hook::CONTEXT_READY`:
```php
Hooks::add(Hook::CONTEXT_READY, function(Context $ctx, array $config) {
$val = $config['my_section']['my_key'] ?? 'default';
$ctx->set('my_val', $val);
return $ctx;
});
```
Config is **not** directly available in templates. Expose values via `Hook::TEMPLATE_VARS`:
```php
Hooks::add(Hook::TEMPLATE_VARS, function(array $vars, Context $ctx) {
global $config;
$vars['siteTitle'] = $config['site']['title'] ?? 'My Site';
return $vars;
});
```
## Content Directory Resolution
In `createContext()`:
1. `$_SERVER['DOCUMENT_ROOT']` is checked for content (>2 entries in scandir)
2. If content exists → use document root as `contentDir`
3. If empty → fall back to `app/default/content/` (demo mode)
Production deployments set Apache's `DocumentRoot` to the content directory. The `app/` and `custom/` directories live outside the document root, accessed via Apache aliases.