Change our template attribute processing, to be collections, so we can find attributes using anycase keys

This commit is contained in:
Deon George 2025-06-22 17:27:56 +10:00
parent ee3cb395c2
commit 3ad4c446ea
5 changed files with 66 additions and 34 deletions

View File

@ -13,7 +13,7 @@ class Template
private const LOGKEY = 'T--';
private(set) string $file;
private array $template;
private Collection $template;
private(set) bool $invalid = FALSE;
private(set) string $reason = '';
private Collection $on_change_target;
@ -31,7 +31,7 @@ class Template
try {
// @todo Load in the proper attribute objects and objectclass objects
// @todo Make sure we have a structural objectclass, or make the template invalid
$this->template = json_decode($td->get($file),null,512,JSON_OBJECT_AS_ARRAY|JSON_THROW_ON_ERROR);
$this->template = collect(json_decode($td->get($file),null,512,JSON_OBJECT_AS_ARRAY|JSON_THROW_ON_ERROR));
} catch (\JsonException $e) {
$this->invalid = TRUE;
@ -42,12 +42,11 @@ class Template
public function __get(string $key): mixed
{
return match ($key) {
'attributes' => collect(Arr::get($this->template,$key))->keys(),
'enabled' => Arr::get($this->template,$key,FALSE) && (! $this->invalid),
'icon','regexp','title' => Arr::get($this->template,$key),
'attributes','objectclasses' => collect($this->template->get($key)),
'enabled' => $this->template->get($key,FALSE) && (! $this->invalid),
'icon','regexp','title' => $this->template->get($key),
'name' => Str::replaceEnd('.json','',$this->file),
'objectclasses' => collect(Arr::get($this->template,$key)),
'order' => collect(Arr::get($this->template,'attributes'))->map(fn($item)=>$item['order']),
'order' => $this->attributes->map(fn($item)=>Arr::get($item,'order')),
default => throw new \Exception('Unknown key: '.$key),
};
@ -55,7 +54,19 @@ class Template
public function __isset(string $key): bool
{
return array_key_exists($key,$this->template);
return $this->template->has($key);
}
/**
* Return the configuration for an attribute
*
* @param string $attribute
* @return array|NULL
*/
public function attribute(string $attribute): Collection|NULL
{
$key = $this->attributes->search(fn($item,$key)=>! strcasecmp($key,$attribute));
return collect($this->attributes->get($key));
}
/**
@ -66,7 +77,7 @@ class Template
*/
public function attributeReadOnly(string $attribute): bool
{
return ($x=Arr::get($this->template,'attributes.'.$attribute.'.readonly')) && $x;
return ($x=$this->attribute($attribute)?->get('readonly')) && $x;
}
/**
@ -77,7 +88,18 @@ class Template
*/
public function attributeTitle(string $attribute): string|NULL
{
return Arr::get($this->template,'attributes.'.$attribute.'.display');
return $this->attribute($attribute)?->get('display');
}
/**
* Return the title we should use for an attribute
*
* @param string $attribute
* @return string|NULL
*/
public function attributeType(string $attribute): string|NULL
{
return $this->attribute($attribute)?->get('type');
}
/**

View File

@ -57,7 +57,7 @@ class HomeController extends Controller
$o->objectclass = [Entry::TAG_NOTAG=>$template->objectclasses->toArray()];
foreach ($o->getAvailableAttributes()
->filter(fn($item)=>$item->names_lc->intersect($template->attributes->map('strtolower'))->count())
->filter(fn($item)=>$item->names_lc->intersect($template->attributes->keys()->map('strtolower'))->count())
->sortBy(fn($item)=>Arr::get($template->order,$item->name)) as $ao)
{
$o->{$ao->name} = [Entry::TAG_NOTAG=>''];

View File

@ -9,13 +9,16 @@
<strong class="align-middle"><abbr title="{{ (($x=$template?->attributeTitle($o->name)) ? $o->name.': ' : '').$o->description }}">{{ $x ?: $o->name }}</abbr></strong>
@if($new)
@if($template?->attributeReadOnly($o->name_lc))
<sup data-bs-toggle="tooltip" title="@lang('Input disabled by template')"><i class="fas fa-ban"></i></sup>
<sup data-bs-toggle="tooltip" title="@lang('Input disabled')"><i class="fas fa-ban"></i></sup>
@endif
@if($template?->onChangeAttribute($o->name_lc))
<sup data-bs-toggle="tooltip" title="@lang('Value triggers an update to another attribute by template')"><i class="fas fa-keyboard"></i></sup>
@if($ca=$template?->onChangeAttribute($o->name_lc))
<sup data-bs-toggle="tooltip" title="@lang('Value triggers an update to another attribute')"><i class="fas fa-keyboard"></i></sup>
@endif
@if ($template?->onChangeTarget($o->name_lc))
<sup data-bs-toggle="tooltip" title="@lang('Value calculated by template')"><i class="fas fa-wand-magic-sparkles"></i></sup>
@if ($ct=$template?->onChangeTarget($o->name_lc))
<sup data-bs-toggle="tooltip" title="@lang('Value calculated from another attribute')"><i class="fas fa-wand-magic-sparkles"></i></sup>
@endif
@if((! $ca) && (! $ct) && $template?->attribute($o->name_lc))
<sup data-bs-toggle="tooltip" title="@lang('Attribute controlled by template')"><i class="fas fa-wand-magic"></i></sup>
@endif
@endif
@ -59,7 +62,13 @@
</div>
</div>
@switch($template?->attributeType($o->name))
@case('type')
@break;
@default
<x-attribute :o="$o" :edit="(! $template?->attributeReadOnly($o->name)) && $edit" :new="$new" :updated="$updated"/>
@endswitch
</div>
</div>

View File

@ -1,31 +1,32 @@
{
"title": "Example entry",
"description": "This is the description",
"enabled": false,
"icon": "fa-star-of-life",
"rdn": "o",
"regexp": "/^$/",
"title": "Example entry", // Title shown when selecting tempaltes
"description": "This is the description", // Unused, only for documenting
"enabled": false, // Whether template is enabled or not
"icon": "fa-star-of-life", // Icon shown when rendering an existing entry that identifies as this template
"rdn": "o", // @todo not implemented
"regexp": "/^$/", // Regular expression that restricts where this template cna be used
"objectclasses": [
"objectclasses": [ // Objectclasses that entries will have if they use this template
"organization"
],
"attributes": {
"attribute1": {
"display": "Attribute 1",
"hint": "This is an example",
"order": 1
"attributes": { // Attribute configuration
"attribute1": { // LDAP attribute name
"display": "Attribute 1", // Displayed when accepting input for this value
"hint": "This is an example", // @todo not implemented
"type": null, // Default is NULL, so use normal Attribute rendering type
"order": 1 // Order to show attributes
},
"attribute2": {
"display": "Attribute 2",
"hint": "This is an example",
"type": "input", // Default is input
"type": "input", // Force attribute to use template input
"order": 2
},
"attribute3": {
"display": "Attribute 3",
"type": "select",
"options": {
"type": "select", // Force attribute to use template select
"options": { // Select options
"/bin/bash": "Bash",
"/bin/csh": "C Shell",
"/bin/dash": "Dash",