Skip to content

Commit b689a65

Browse files
Merge pull request #88 from Relaticle/feat/scoped-management-feature
feat: add scoped management feature and section form extensibility
2 parents 9aa15e6 + ff0d93a commit b689a65

File tree

6 files changed

+67
-31
lines changed

6 files changed

+67
-31
lines changed

src/EntitySystem/EntityCollection.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ public function withCustomFields(): static
5252
);
5353
}
5454

55+
/**
56+
* Get entities with custom fields that are globally managed (not scoped to a parent record)
57+
*/
58+
public function globallyManaged(): static
59+
{
60+
return $this->withCustomFields()->withoutFeature(EntityFeature::SCOPED_MANAGEMENT->value);
61+
}
62+
5563
/**
5664
* Get entities that can be used as lookup sources
5765
*/

src/Enums/EntityFeature.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ enum EntityFeature: string implements HasLabel
1313
{
1414
case CUSTOM_FIELDS = 'custom_fields';
1515
case LOOKUP_SOURCE = 'lookup_source';
16+
case SCOPED_MANAGEMENT = 'scoped_management';
1617

1718
public function getLabel(): string
1819
{
1920
return match ($this) {
2021
self::CUSTOM_FIELDS => 'Custom Fields',
2122
self::LOOKUP_SOURCE => 'Lookup Source',
23+
self::SCOPED_MANAGEMENT => 'Scoped Management',
2224
};
2325
}
2426

@@ -27,6 +29,7 @@ public function description(): string
2729
return match ($this) {
2830
self::CUSTOM_FIELDS => 'Entity can have custom fields attached',
2931
self::LOOKUP_SOURCE => 'Entity can be used as a lookup source for choice fields',
32+
self::SCOPED_MANAGEMENT => 'Entity custom fields are managed per-parent record, not on the global management page',
3033
};
3134
}
3235
}

src/Facades/Entities.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ public static function withCustomFields(): EntityCollection
8686
return static::getEntities()->withCustomFields();
8787
}
8888

89+
/**
90+
* Get entities with custom fields that are globally managed
91+
*/
92+
public static function globallyManaged(): EntityCollection
93+
{
94+
return static::getEntities()->globallyManaged();
95+
}
96+
8997
/**
9098
* Get entities that can be used as lookup sources
9199
*/
@@ -97,11 +105,13 @@ public static function asLookupSources(): EntityCollection
97105
/**
98106
* Get entities as options array
99107
*/
100-
public static function getOptions(bool $onlyCustomFields = true, bool $usePlural = true): array
108+
public static function getOptions(bool $onlyCustomFields = true, bool $usePlural = true, bool $onlyGloballyManaged = false): array
101109
{
102-
$entities = $onlyCustomFields
103-
? static::withCustomFields()
104-
: static::getEntities();
110+
$entities = match (true) {
111+
$onlyGloballyManaged => static::globallyManaged(),
112+
$onlyCustomFields => static::withCustomFields(),
113+
default => static::getEntities(),
114+
};
105115

106116
return $entities->sortedByLabel()->toOptions($usePlural);
107117
}

src/Filament/Integration/Base/AbstractFormComponent.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ protected function configure(
6666
filled($state)
6767
)
6868
->required($this->validationService->isRequired($customField))
69-
->rules($this->validationService->getValidationRules($customField))
69+
->rules($this->getFieldValidationRules($customField))
7070
->columnSpan($customField->width->getSpanValue())
7171
->when(
7272
FeatureManager::isEnabled(CustomFieldsFeature::FIELD_CONDITIONAL_VISIBILITY) &&
@@ -123,6 +123,12 @@ private function applyVisibility(
123123
: $field->live()->visibleJs($jsExpression);
124124
}
125125

126+
/** @return array<int, mixed> */
127+
protected function getFieldValidationRules(CustomField $customField): array
128+
{
129+
return $this->validationService->getValidationRules($customField);
130+
}
131+
126132
/**
127133
* Apply settings dynamically to any Filament component
128134
*/

src/Filament/Management/Pages/CustomFieldsManagementPage.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class CustomFieldsManagementPage extends Page
4343
public function mount(): void
4444
{
4545
if (blank($this->currentEntityType)) {
46-
$firstEntity = Entities::withCustomFields()->first();
46+
$firstEntity = Entities::globallyManaged()->first();
4747
$this->setCurrentEntityType($firstEntity?->getAlias() ?? '');
4848
}
4949
}
@@ -91,7 +91,7 @@ public function currentEntityIcon(): string
9191
#[Computed]
9292
public function entityTypes(): Collection
9393
{
94-
return collect(Entities::getOptions(onlyCustomFields: true));
94+
return collect(Entities::getOptions(onlyGloballyManaged: true));
9595
}
9696

9797
public function setCurrentEntityType(?string $entityType): void

src/Filament/Management/Schemas/SectionForm.php

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,48 @@
1717
use Relaticle\CustomFields\Enums\CustomFieldSectionType;
1818
use Relaticle\CustomFields\Enums\CustomFieldsFeature;
1919
use Relaticle\CustomFields\FeatureSystem\FeatureManager;
20+
use Relaticle\CustomFields\Models\CustomFieldSection;
2021
use Relaticle\CustomFields\Services\TenantContextService;
2122

2223
class SectionForm implements FormInterface, SectionFormInterface
2324
{
2425
private static string $entityType;
2526

27+
/** @var ?\Closure(Unique, Get): Unique */
28+
private static ?\Closure $modifyUniqueRuleUsing = null;
29+
2630
public static function entityType(string $entityType): self
2731
{
2832
self::$entityType = $entityType;
33+
self::$modifyUniqueRuleUsing = null;
2934

3035
return new self;
3136
}
3237

38+
public function modifyUniqueRuleUsing(\Closure $callback): self
39+
{
40+
self::$modifyUniqueRuleUsing = $callback;
41+
42+
return $this;
43+
}
44+
45+
private static function buildUniqueRule(Unique $rule, Get $get): Unique
46+
{
47+
$rule = $rule->when(
48+
FeatureManager::isEnabled(CustomFieldsFeature::SYSTEM_MULTI_TENANCY),
49+
fn (Unique $rule) => $rule->where(
50+
config('custom-fields.database.column_names.tenant_foreign_key'),
51+
TenantContextService::getCurrentTenantId()
52+
)
53+
)->where('entity_type', self::$entityType);
54+
55+
if (self::$modifyUniqueRuleUsing) {
56+
$rule = (self::$modifyUniqueRuleUsing)($rule, $get);
57+
}
58+
59+
return $rule;
60+
}
61+
3362
/**
3463
* @return array<int, Component>
3564
*/
@@ -47,18 +76,8 @@ public static function schema(): array
4776
->unique(
4877
table: CustomFields::sectionModel(),
4978
column: 'name',
50-
ignoreRecord: true,
51-
modifyRuleUsing: fn (Unique $rule, Get $get) => $rule
52-
->when(
53-
FeatureManager::isEnabled(CustomFieldsFeature::SYSTEM_MULTI_TENANCY),
54-
fn (Unique $rule) => $rule->where(
55-
config(
56-
'custom-fields.database.column_names.tenant_foreign_key'
57-
),
58-
TenantContextService::getCurrentTenantId()
59-
)
60-
)
61-
->where('entity_type', self::$entityType)
79+
ignorable: fn (TextInput $component) => ($record = $component->getRecord()) instanceof CustomFieldSection ? $record : null,
80+
modifyRuleUsing: fn (Unique $rule, Get $get) => self::buildUniqueRule($rule, $get),
6281
)
6382
->afterStateUpdated(function (
6483
Get $get,
@@ -89,18 +108,8 @@ public static function schema(): array
89108
->unique(
90109
table: CustomFields::sectionModel(),
91110
column: 'code',
92-
ignoreRecord: true,
93-
modifyRuleUsing: fn (Unique $rule, Get $get) => $rule
94-
->when(
95-
FeatureManager::isEnabled(CustomFieldsFeature::SYSTEM_MULTI_TENANCY),
96-
fn (Unique $rule) => $rule->where(
97-
config(
98-
'custom-fields.database.column_names.tenant_foreign_key'
99-
),
100-
TenantContextService::getCurrentTenantId()
101-
)
102-
)
103-
->where('entity_type', self::$entityType)
111+
ignorable: fn (TextInput $component) => ($record = $component->getRecord()) instanceof CustomFieldSection ? $record : null,
112+
modifyRuleUsing: fn (Unique $rule, Get $get) => self::buildUniqueRule($rule, $get),
104113
)
105114
->afterStateUpdated(function (
106115
Set $set,

0 commit comments

Comments
 (0)