Optimize schema objectclass processing, changing debugging output, remove redundant functions

This commit is contained in:
Deon George 2025-06-12 13:01:05 +09:30
parent 56fcd729e7
commit acf19cdc5b
5 changed files with 262 additions and 417 deletions

View File

@ -2,6 +2,8 @@
namespace App\Classes\LDAP\Schema; namespace App\Classes\LDAP\Schema;
use Illuminate\Support\Facades\Log;
use App\Exceptions\InvalidUsage; use App\Exceptions\InvalidUsage;
/** /**
@ -10,38 +12,38 @@ use App\Exceptions\InvalidUsage;
* A schema item is an ObjectClass, an AttributeBype, a MatchingRule, or a Syntax. * A schema item is an ObjectClass, an AttributeBype, a MatchingRule, or a Syntax.
* All schema items have at least two things in common: An OID and a Description. * All schema items have at least two things in common: An OID and a Description.
*/ */
abstract class Base { abstract class Base
{
private const LOGKEY = 'Sb-';
protected const DEBUG_VERBOSE = FALSE; protected const DEBUG_VERBOSE = FALSE;
// Record the LDAP String // Record the LDAP String
private string $line; private(set) string $line;
// The schema item's name. // The schema item's name.
protected string $name = ''; protected(set) string $name = '';
// The OID of this schema item. // The OID of this schema item.
protected string $oid = ''; protected(set) string $oid = '';
# The description of this schema item. # The description of this schema item.
protected string $description = ''; protected(set) string $description = '';
// Boolean value indicating whether this objectClass is obsolete // Boolean value indicating whether this objectClass is obsolete
private bool $is_obsolete = FALSE; private(set) bool $is_obsolete = FALSE;
public function __construct(string $line) public function __construct(string $line)
{ {
$this->line = $line; $this->line = $line;
$this->parse($line);
} }
public function __get(string $key): mixed public function __get(string $key): mixed
{ {
switch ($key) { switch ($key) {
case 'description': return $this->description;
case 'is_obsolete': return $this->is_obsolete;
case 'line': return $this->line;
case 'name': return $this->name;
case 'name_lc': return strtolower($this->name); case 'name_lc': return strtolower($this->name);
case 'oid': return $this->oid;
default: default:
throw new InvalidUsage('Unknown key:'.$key); throw new InvalidUsage('Unknown key:'.$key);
@ -58,65 +60,91 @@ abstract class Base {
return $this->name; return $this->name;
} }
/** protected function parse(string $line): void
* @return string
* @deprecated replace with $class->description
*/
public function getDescription(): string
{ {
return $this->description; $strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
for ($i=0; $i < count($strings); $i++) {
$this->parse_chunk($strings,$i);
}
} }
/** protected function parse_chunk(array $strings,int &$i): void
* Gets whether this item is flagged as obsolete by the LDAP server.
*
* @deprecated replace with $this->is_obsolete
*/
public function getIsObsolete(): bool
{ {
return $this->is_obsolete; switch ($strings[$i]) {
} case '(':
case ')':
break;
/** case 'NAME':
* Return the objects name. if ($strings[$i+1] !== '(') {
* do {
* @param boolean $lower Return the name in lower case (default) $this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
* @return string The name } while (! preg_match('/\'$/s',$strings[$i]));
* @deprecated use object->name
*/
public function getName(bool $lower=TRUE): string
{
return $lower ? strtolower($this->name) : $this->name;
}
/** } else {
* Return the objects name. $i++;
*
* @return string The name
* @deprecated use object->oid
*/
public function getOID(): string
{
return $this->oid;
}
public function setDescription(string $desc): void do {
{ $this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
$this->description = $desc; } while (! preg_match('/\'$/s',$strings[$i]));
}
/** do {
* Sets this attribute's name. $i++;
* } while (! preg_match('/\)+\)?/',$strings[$i]));
* @param string $name The new name to give this attribute. }
*/
public function setName($name): void
{
$this->name = $name;
}
public function setOID(string $oid): void $this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
{
$this->oid = $oid; if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case NAME returned (%s)',self::LOGKEY,$this->name));
break;
case 'DESC':
do {
$this->description .= (strlen($this->description) ? ' ' : '').$strings[++$i];
} while (! preg_match('/\'$/s',$strings[$i]));
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case DESC returned (%s)',self::LOGKEY,$this->description));
break;
case 'OBSOLETE':
$this->is_obsolete = TRUE;
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case OBSOLETE returned (%s)',self::LOGKEY,$this->is_obsolete));
break;
// @note currently not captured
case 'X-SUBST':
case 'X-ORDERED':
case 'X-EQUALITY':
case 'X-ORIGIN':
$value = '';
do {
$value .= ($value ? ' ' : '').preg_replace('/^\'(.+)\'$/','$1',$strings[++$i]);
} while (! preg_match("/\'$/s",$strings[$i]));
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case [%s] returned (%s) - IGNORED',self::LOGKEY,$strings[$i],$value));
break;
default:
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
$this->oid = $strings[$i];
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case default returned OID (%s)',self::LOGKEY,$this->oid));
} elseif ($strings[$i])
Log::alert(sprintf('%s:! Case default discovered a value NOT parsed (%s)',self::LOGKEY,$strings[$i]));
}
} }
} }

View File

@ -16,8 +16,13 @@ use App\Exceptions\InvalidUsage;
*/ */
final class ObjectClass extends Base final class ObjectClass extends Base
{ {
private const LOGKEY = 'SOC';
// Array of objectClasses which inherit from this one
private(set) Collection $child_classes;
// Array of objectClass names from which this objectClass inherits // Array of objectClass names from which this objectClass inherits
private Collection $sup_classes; private(set) Collection $sup_classes;
// One of STRUCTURAL, ABSTRACT, or AUXILIARY // One of STRUCTURAL, ABSTRACT, or AUXILIARY
private int $type; private int $type;
@ -29,187 +34,14 @@ final class ObjectClass extends Base
private Collection $may_attrs; private Collection $may_attrs;
// Arrays of attribute names that this objectClass has been forced to MAY attrs, due to configuration // Arrays of attribute names that this objectClass has been forced to MAY attrs, due to configuration
private Collection $may_force; private(set) Collection $may_force;
// Array of objectClasses which inherit from this one
private Collection $child_objectclasses;
private bool $is_obsolete; private bool $is_obsolete;
/**
* Creates a new ObjectClass object given a raw LDAP objectClass string.
*
* eg: ( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )
*
* @param string $line Schema Line
* @param Server $server
* @todo Deprecate this $server variable? It is only used for isForceMay() determination, and that might be better done elsewhere?
*/
public function __construct(string $line,Server $server)
{
parent::__construct($line);
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('Parsing ObjectClass [%s]',$line));
$strings = preg_split('/[\s,]+/',$line,-1,PREG_SPLIT_DELIM_CAPTURE);
// Init
$this->may_attrs = collect();
$this->may_force = collect();
$this->must_attrs = collect();
$this->sup_classes = collect();
$this->child_objectclasses = collect();
for ($i=0; $i < count($strings); $i++) {
switch ($strings[$i]) {
case '(':
case ')':
break;
case 'NAME':
if ($strings[$i+1] != '(') {
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match('/\'$/s',$strings[$i]));
} else {
$i++;
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match('/\'$/s',$strings[$i]));
do {
$i++;
} while (! preg_match('/\)+\)?/',$strings[$i]));
}
$this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
if (static::DEBUG_VERBOSE)
Log::debug(sprintf(sprintf('- Case NAME returned (%s)',$this->name)));
break;
case 'DESC':
do {
$this->description .= (strlen($this->description) ? ' ' : '').$strings[++$i];
} while (! preg_match('/\'$/s',$strings[$i]));
$this->description = preg_replace("/^\'(.*)\'$/",'$1',$this->description);
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('- Case DESC returned (%s)',$this->description));
break;
case 'OBSOLETE':
$this->is_obsolete = TRUE;
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('- Case OBSOLETE returned (%s)',$this->is_obsolete));
break;
case 'SUP':
if ($strings[$i+1] != '(') {
$this->sup_classes->push(preg_replace("/'/",'',$strings[++$i]));
} else {
$i++;
do {
$i++;
if ($strings[$i] != '$')
$this->sup_classes->push(preg_replace("/'/",'',$strings[$i]));
} while (! preg_match('/\)+\)?/',$strings[$i+1]));
}
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('- Case SUP returned (%s)',$this->sup_classes->join(',')));
break;
case 'ABSTRACT':
$this->type = Server::OC_ABSTRACT;
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('- Case ABSTRACT returned (%s)',$this->type));
break;
case 'STRUCTURAL':
$this->type = Server::OC_STRUCTURAL;
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('- Case STRUCTURAL returned (%s)',$this->type));
break;
case 'AUXILIARY':
$this->type = Server::OC_AUXILIARY;
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('- Case AUXILIARY returned (%s)',$this->type));
break;
case 'MUST':
$attrs = collect();
$i = $this->parseList(++$i,$strings,$attrs);
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('= parseList returned %d (%s)',$i,$attrs->join(',')));
foreach ($attrs as $string) {
$attr = new ObjectClassAttribute($string,$this->name);
if ($server->isForceMay($attr->getName())) {
$this->may_force->push($attr);
$this->may_attrs->push($attr);
} else
$this->must_attrs->push($attr);
}
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('- Case MUST returned (%s) (%s)',$this->must_attrs->join(','),$this->may_force->join(',')));
break;
case 'MAY':
$attrs = collect();
$i = $this->parseList(++$i,$strings,$attrs);
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('parseList returned %d (%s)',$i,$attrs->join(',')));
foreach ($attrs as $string) {
$attr = new ObjectClassAttribute($string,$this->name);
$this->may_attrs->push($attr);
}
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('- Case MAY returned (%s)',$this->may_attrs->join(',')));
break;
default:
if (preg_match('/[\d\.]+/i',$strings[$i]) && ($i === 1)) {
$this->oid = $strings[$i];
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('- Case default returned (%s)',$this->oid));
} elseif ($strings[$i])
Log::alert(sprintf('! Case default discovered a value NOT parsed (%s)',$strings[$i]),['line'=>$line]);
}
}
}
public function __get(string $key): mixed public function __get(string $key): mixed
{ {
return match ($key) { return match ($key) {
'attributes' => $this->getAllAttrs(TRUE), 'attributes' => $this->getAllAttrs(TRUE),
'sup' => $this->sup_classes,
'type_name' => match ($this->type) { 'type_name' => match ($this->type) {
Server::OC_STRUCTURAL => 'Structural', Server::OC_STRUCTURAL => 'Structural',
Server::OC_ABSTRACT => 'Abstract', Server::OC_ABSTRACT => 'Abstract',
@ -229,11 +61,8 @@ final class ObjectClass extends Base
*/ */
public function getAllAttrs(bool $parents=FALSE): Collection public function getAllAttrs(bool $parents=FALSE): Collection
{ {
return $this->getMustAttrs($parents) return $this
->transform(function($item) { ->getMustAttrs($parents)
$item->required = true;
return $item;
})
->merge($this->getMayAttrs($parents)); ->merge($this->getMayAttrs($parents));
} }
@ -245,57 +74,8 @@ final class ObjectClass extends Base
*/ */
public function addChildObjectClass(string $name): void public function addChildObjectClass(string $name): void
{ {
if (! $this->child_objectclasses->contains($name)) if (! $this->child_classes->contains($name))
$this->child_objectclasses->push($name); $this->child_classes->push($name);
}
/**
* Returns the array of objectClass names which inherit from this objectClass.
*
* @return Collection Names of objectClasses which inherit from this objectClass.
* @deprecated use $this->child_objectclasses
*/
public function getChildObjectClasses(): Collection
{
return $this->child_objectclasses;
}
/**
* Behaves identically to addMustAttrs, but it operates on the MAY
* attributes of this objectClass.
*
* @param array $attr An array of attribute names (strings) to add.
*/
private function addMayAttrs(array $attr): void
{
if (! is_array($attr) || ! count($attr))
return;
$this->may_attrs = $this->may_attrs->merge($attr)->unique();
}
/**
* Adds the specified array of attributes to this objectClass' list of
* MUST attributes. The resulting array of must attributes will contain
* unique members.
*
* @param array $attr An array of attribute names (strings) to add.
*/
private function addMustAttrs(array $attr): void
{
if (! is_array($attr) || ! count($attr))
return;
$this->must_attrs = $this->must_attrs->merge($attr)->unique();
}
/**
* @return Collection
* @deprecated use $this->may_force
*/
public function getForceMayAttrs(): Collection
{
return $this->may_force;
} }
/** /**
@ -313,42 +93,16 @@ final class ObjectClass extends Base
*/ */
public function getMayAttrs(bool $parents=FALSE): Collection public function getMayAttrs(bool $parents=FALSE): Collection
{ {
// If we dont need our parents, then we'll just return ours.
if (! $parents)
return $this->may_attrs
->sortBy(fn($item)=>strtolower($item->name.$item->source));
$attrs = $this->may_attrs; $attrs = $this->may_attrs;
foreach ($this->getParents() as $object_class) if ($parents)
$attrs = $attrs->merge($object_class->getMayAttrs($parents)); foreach ($this->getParents() as $object_class)
$attrs = $attrs->merge($object_class->getMayAttrs($parents));
// Remove any duplicates
$attrs = $attrs->unique(function($item) { return $item->name; });
// Return a sorted list // Return a sorted list
return $attrs->sortBy(function($item) { return strtolower($item->name.$item->source); }); return $attrs
} ->unique(fn($item)=>$item->name)
->sortBy(fn($item)=>strtolower($item->name.$item->source));
/**
* Gets an array of attribute names (strings) that entries of this ObjectClass must define.
* This differs from getMayAttrs in that it returns an array of strings rather than
* array of AttributeType objects
*
* @param bool $parents An array of ObjectClass objects to use when traversing
* the inheritance tree. This presents some what of a bootstrapping problem
* as we must fetch all objectClasses to determine through inheritance which
* attributes this objectClass provides.
* @return Collection The array of allowed attribute names (strings).
*
* @throws InvalidUsage
* @see getMustAttrs
* @see getMayAttrs
* @see getMustAttrNames
*/
public function getMayAttrNames(bool $parents=FALSE): Collection
{
return $this->getMayAttrs($parents)->ppluck('name');
} }
/** /**
@ -365,41 +119,16 @@ final class ObjectClass extends Base
*/ */
public function getMustAttrs(bool $parents=FALSE): Collection public function getMustAttrs(bool $parents=FALSE): Collection
{ {
// If we dont need our parents, then we'll just return ours.
if (! $parents)
return $this->must_attrs->sortBy(function($item) { return strtolower($item->name.$item->source); });
$attrs = $this->must_attrs; $attrs = $this->must_attrs;
foreach ($this->getParents() as $object_class) if ($parents)
$attrs = $attrs->merge($object_class->getMustAttrs($parents)); foreach ($this->getParents() as $object_class)
$attrs = $attrs->merge($object_class->getMustAttrs($parents));
// Remove any duplicates
$attrs = $attrs->unique(function($item) { return $item->name; });
// Return a sorted list // Return a sorted list
return $attrs->sortBy(function($item) { return strtolower($item->name.$item->source); }); return $attrs
} ->unique(fn($item)=>$item->name)
->sortBy(fn($item)=>strtolower($item->name.$item->source));
/**
* Gets an array of attribute names (strings) that entries of this ObjectClass must define.
* This differs from getMustAttrs in that it returns an array of strings rather than
* array of AttributeType objects
*
* @param bool $parents An array of ObjectClass objects to use when traversing
* the inheritance tree. This presents some what of a bootstrapping problem
* as we must fetch all objectClasses to determine through inheritance which
* attributes this objectClass provides.
* @return Collection The array of allowed attribute names (strings).
*
* @throws InvalidUsage
* @see getMustAttrs
* @see getMayAttrs
* @see getMayAttrNames
*/
public function getMustAttrNames(bool $parents=FALSE): Collection
{
return $this->getMustAttrs($parents)->ppluck('name');
} }
/** /**
@ -426,27 +155,6 @@ final class ObjectClass extends Base
return $result; return $result;
} }
/**
* Gets the objectClass names from which this objectClass inherits.
*
* @return Collection An array of objectClass names (strings)
* @deprecated use $this->sup_classes;
*/
public function getSupClasses(): Collection
{
return $this->sup_classes;
}
/**
* Gets the type of this objectClass: STRUCTURAL, ABSTRACT, or AUXILIARY.
*
* @deprecated use $this->type_name
*/
public function getType()
{
return $this->type;
}
/** /**
* Return if this objectclass is auxiliary * Return if this objectclass is auxiliary
* *
@ -462,27 +170,9 @@ final class ObjectClass extends Base
*/ */
public function isForceMay(string $attr): bool public function isForceMay(string $attr): bool
{ {
return $this->may_force->ppluck('name')->contains($attr); return $this->may_force
} ->pluck('name')
->contains($attr);
/**
* Return if this objectClass is related to $oclass
*
* @param array $oclass ObjectClasses that this attribute may be related to
* @return bool
* @throws InvalidUsage
*/
public function isRelated(array $oclass): bool
{
// If I am in the array, we'll just return false
if (in_array_ignore_case($this->name,$oclass))
return FALSE;
foreach ($oclass as $object_class)
if ($object_class->isStructural() && in_array_ignore_case($this->name,$object_class->getParents()->pluck('name')))
return TRUE;
return FALSE;
} }
public function isStructural(): bool public function isStructural(): bool
@ -490,6 +180,143 @@ final class ObjectClass extends Base
return $this->type === Server::OC_STRUCTURAL; return $this->type === Server::OC_STRUCTURAL;
} }
/**
* Creates a new ObjectClass object given a raw LDAP objectClass string.
*
* eg: ( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )
*
* @param string $line Schema Line
*/
protected function parse(string $line): void
{
Log::debug(sprintf('%s:Parsing ObjectClass [%s]',self::LOGKEY,$line));
// Init
$this->may_attrs = collect();
$this->may_force = collect();
$this->must_attrs = collect();
$this->sup_classes = collect();
$this->child_classes = collect();
parent::parse($line);
}
protected function parse_chunk(array $strings,int &$i): void
{
switch ($strings[$i]) {
case 'NAME':
if ($strings[$i+1] != '(') {
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match('/\'$/s',$strings[$i]));
} else {
$i++;
do {
$this->name .= (strlen($this->name) ? ' ' : '').$strings[++$i];
} while (! preg_match('/\'$/s',$strings[$i]));
do {
$i++;
} while (! preg_match('/\)+\)?/',$strings[$i]));
}
$this->name = preg_replace("/^\'(.*)\'$/",'$1',$this->name);
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case NAME returned (%s)',self::LOGKEY,$this->name));
break;
case 'SUP':
if ($strings[$i+1] != '(') {
$this->sup_classes->push(preg_replace("/'/",'',$strings[++$i]));
} else {
$i++;
do {
$i++;
if ($strings[$i] != '$')
$this->sup_classes->push(preg_replace("/'/",'',$strings[$i]));
} while (! preg_match('/\)+\)?/',$strings[$i+1]));
}
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case SUP returned (%s)',self::LOGKEY,$this->sup_classes->join(',')));
break;
case 'ABSTRACT':
$this->type = Server::OC_ABSTRACT;
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case ABSTRACT returned (%s)',self::LOGKEY,$this->type));
break;
case 'STRUCTURAL':
$this->type = Server::OC_STRUCTURAL;
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case STRUCTURAL returned (%s)',self::LOGKEY,$this->type));
break;
case 'AUXILIARY':
$this->type = Server::OC_AUXILIARY;
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case AUXILIARY returned (%s)',self::LOGKEY,$this->type));
break;
case 'MUST':
$attrs = collect();
$i = $this->parseList(++$i,$strings,$attrs);
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:= parseList returned %d (%s)',self::LOGKEY,$i,$attrs->join(',')));
foreach ($attrs as $string) {
$attr = new ObjectClassAttribute($string,$this->name);
if (config('server')->isForceMay($attr->getName())) {
$this->may_force->push($attr);
$this->may_attrs->push($attr);
} else
$attr->required = TRUE;
$this->must_attrs->push($attr);
}
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case MUST returned (%s) (%s)',self::LOGKEY,$this->must_attrs->join(','),$this->may_force->join(',')));
break;
case 'MAY':
$attrs = collect();
$i = $this->parseList(++$i,$strings,$attrs);
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- parseList returned %d (%s)',self::LOGKEY,$i,$attrs->join(',')));
foreach ($attrs as $string) {
$attr = new ObjectClassAttribute($string,$this->name);
$this->may_attrs->push($attr);
}
if (static::DEBUG_VERBOSE)
Log::debug(sprintf('%s:- Case MAY returned (%s)',self::LOGKEY,$this->may_attrs->join(',')));
break;
default:
parent::parse_chunk($strings,$i);
}
}
/** /**
* Parse an LDAP schema list * Parse an LDAP schema list
* *

View File

@ -30,7 +30,7 @@ final class Server
private Collection $matchingrules; private Collection $matchingrules;
private Collection $objectclasses; private Collection $objectclasses;
private Entry $rootDSE; private Model $rootDSE;
/* ObjectClass Types */ /* ObjectClass Types */
public const OC_STRUCTURAL = 0x01; public const OC_STRUCTURAL = 0x01;
@ -418,22 +418,18 @@ final class Server
// Add the used in and required_by values. // Add the used in and required_by values.
foreach ($this->schema('objectclasses') as $object_class) { foreach ($this->schema('objectclasses') as $object_class) {
$must_attrs = $object_class->getMustAttrNames();
$may_attrs = $object_class->getMayAttrNames();
$oclass_attrs = $must_attrs->merge($may_attrs)->unique();
// Add Used In. // Add Used In.
foreach ($oclass_attrs as $attr_name) foreach ($object_class->getAllAttrs()->pluck('name') as $attr_name)
if ($this->attributetypes->has(strtolower($attr_name))) if ($this->attributetypes->has(strtolower($attr_name)))
$this->attributetypes[strtolower($attr_name)]->addUsedInObjectClass($object_class->name,$object_class->isStructural()); $this->attributetypes[strtolower($attr_name)]->addUsedInObjectClass($object_class->name,$object_class->isStructural());
// Add Required By. // Add Required By.
foreach ($must_attrs as $attr_name) foreach ($object_class->getMustAttrs()->pluck('name') as $attr_name)
if ($this->attributetypes->has(strtolower($attr_name))) if ($this->attributetypes->has(strtolower($attr_name)))
$this->attributetypes[strtolower($attr_name)]->addRequiredByObjectClass($object_class->name,$object_class->isStructural()); $this->attributetypes[strtolower($attr_name)]->addRequiredByObjectClass($object_class->name,$object_class->isStructural());
// Force May // Force May
foreach ($object_class->getForceMayAttrs() as $attr_name) foreach ($object_class->may_force as $attr_name)
if ($this->attributetypes->has(strtolower($attr_name->name))) if ($this->attributetypes->has(strtolower($attr_name->name)))
$this->attributetypes[strtolower($attr_name->name)]->setForceMay(); $this->attributetypes[strtolower($attr_name->name)]->setForceMay();
} }
@ -486,7 +482,7 @@ final class Server
// Now go through and reference the parent/child relationships // Now go through and reference the parent/child relationships
foreach ($this->objectclasses as $o) foreach ($this->objectclasses as $o)
foreach ($o->getSupClasses() as $parent) { foreach ($o->sup_classes as $parent) {
$parent = strtolower($parent); $parent = strtolower($parent);
if (! $this->objectclasses->contains($parent)) if (! $this->objectclasses->contains($parent))

View File

@ -29,11 +29,5 @@ class AppServiceProvider extends ServiceProvider
public function boot(): void public function boot(): void
{ {
$this->loadViewsFrom(__DIR__.'/../../resources/themes/architect/views/','architect'); $this->loadViewsFrom(__DIR__.'/../../resources/themes/architect/views/','architect');
// Enable pluck on collections to work on private values
Collection::macro('ppluck',
fn($attr)=>$this
->map(fn($item)=>$item->{$attr})
->values());
} }
} }

View File

@ -35,10 +35,10 @@
<td>@lang('Inherits from')</td> <td>@lang('Inherits from')</td>
<td colspan="3"> <td colspan="3">
<strong> <strong>
@if($o->sup->count() === 0) @if($o->sup_classes->count() === 0)
@lang('(none)') @lang('(none)')
@else @else
@foreach($o->sup as $sup) @foreach($o->sup_classes as $sup)
@if($loop->index)</strong> <strong>@endif @if($loop->index)</strong> <strong>@endif
<a class="objectclass" id="{{ strtolower($sup) }}" href="#{{ strtolower($sup) }}">{{ $sup }}</a> <a class="objectclass" id="{{ strtolower($sup) }}" href="#{{ strtolower($sup) }}">{{ $sup }}</a>
@endforeach @endforeach
@ -53,10 +53,10 @@
<strong> <strong>
@if(strtolower($o->name) === 'top') @if(strtolower($o->name) === 'top')
<a class="objectclass" id="-all-">(all)</a> <a class="objectclass" id="-all-">(all)</a>
@elseif(! $o->getChildObjectClasses()->count()) @elseif(! $o->child_classes->count())
@lang('(none)') @lang('(none)')
@else @else
@foreach($o->getChildObjectClasses() as $childoc) @foreach($o->child_classes as $childoc)
@if($loop->index)</strong> <strong>@endif @if($loop->index)</strong> <strong>@endif
<a class="objectclass" id="{{ strtolower($childoc) }}" href="#{{ strtolower($childoc) }}">{{ $childoc }}</a> <a class="objectclass" id="{{ strtolower($childoc) }}" href="#{{ strtolower($childoc) }}">{{ $childoc }}</a>
@endforeach @endforeach