1: <?php
2:
3: namespace LaravelUi5\Core\Attributes;
4:
5: use LaravelUi5\Core\Enums\SettingScope;
6: use LaravelUi5\Core\Enums\ValueType;
7: use LaravelUi5\Core\Enums\SettingVisibilityRole;
8:
9: /**
10: * Declarative setting definition for Configurable classes.
11: *
12: * Apply this attribute multiple times on a class (e.g., Action handler, Resource/Data provider,
13: * Report provider) to declare the settings it depends on.
14: *
15: * **When to Use Settings vs. Custom Database Models**
16: *
17: * The *Settings API* is designed for lightweight, flexible configuration values that can be expressed as simple key–value pairs (strings, numbers, booleans, arrays, dates).
18: * It works well when the configuration is *UI-driven, ephemeral, or low-risk*:
19: *
20: * - UI filters and personalization (e.g., a card showing weekly hours for selected employees).
21: * - Display preferences (e.g., default currency, theme, date range presets).
22: * - Feature toggles or thresholds that may change frequently.
23: * - Lists of IDs that serve as filters, *as long as you accept weak references* (IDs stored without DB-level foreign keys).
24: *
25: * By contrast, a *custom database model* should be used when the configuration expresses a *business relationship or critical domain rule*:
26: *
27: * - Relationships that must be referentially intact (e.g., employees assigned to cost centers).
28: * - Audit-relevant or legally binding data (e.g., who is eligible for billing, regulatory roles).
29: * - Data that requires strong constraints, migrations, or reporting queries (joins, aggregates).
30: * - Long-lived associations where zombie IDs (deleted or reassigned objects) are unacceptable.
31: *
32: * **Rule of Thumb**
33: *
34: * If a value is *ephemeral, UI-scoped, or best-effort* → *Settings* are pragmatic and safe.
35: * If a value is *domain-critical, audited, or relational in nature* → design a *dedicated DB model*.
36: *
37: * **Notes**
38: *
39: * Weak foreign keys in Settings (e.g., arrays of BusinessPartner IDs) are acceptable if you *sanitize them at runtime* (ignore IDs that no longer exist).
40: * Settings should always store JSON-safe primitives (string, int, float, bool, date in ISO-8601, arrays thereof).
41: * You trade off *referential integrity* for *developer speed*. This is intentional.
42: *
43: * **Example**
44: *
45: * ```#[Setting(
46: * key: 'billing.settlement.validation.maxHours',
47: * type: ValueType::Integer,
48: * default: 8,
49: * scope: SettingScope::Tenant,
50: * visibilityRole: SettingVisibilityRole::TenantAdmin
51: * )]```
52: */
53: #[\Attribute(\Attribute::TARGET_CLASS | \Attribute::IS_REPEATABLE)]
54: class Setting
55: {
56: /**
57: * @param string $setting Technical identifier, e.g. "module.service.setting.foo.bar"
58: * @param ValueType $type Type used to cast the JSON value (maps to `value_type`)
59: * @param mixed $default Default applied by package (developer)
60: * @param SettingScope $scope Intended/default scope for this setting (maps to `scope`)
61: * @param SettingVisibilityRole $role Minimum role allowed to edit (maps to `visibility_role`)
62: * @param string $note Description of the setting's purpose or scope.
63: */
64: public function __construct(
65: public string $setting,
66: public ValueType $type = ValueType::String,
67: public mixed $default = null,
68: public SettingScope $scope = SettingScope::Tenant,
69: public SettingVisibilityRole $role = SettingVisibilityRole::TenantAdmin,
70: public string $note,
71: )
72: {
73: }
74: }
75: