Update AGENT.md to reflect current project structure and philosophy Add comprehensive architecture documentation covering: - Directory layout - Stable contracts - Request flow - Module dependencies - Page vs list detection - Deployment models - Demo fallback Remove outdated plugin system documentation Add new content system documentation Add configuration documentation Add context API documentation Add hooks and plugins documentation Add templates documentation Add rendering documentation Add development environment documentation
114 lines
3.9 KiB
Markdown
114 lines
3.9 KiB
Markdown
# 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.
|