$this->ldapSyntaxes, "attribute_types" => $this->attributeTypes, "object_classes" => $this->objectClasses, ] = $schemaInfos; } } protected $ldapSyntaxes; protected $attributeTypes; protected $objectClasses; function loadSchema(LdapConn $conn): array { $schema = null; $schemaDn = $conn->getRootDse()->first("subschemaSubentry"); if ($schemaDn !== null) { $schema = $conn->empty()->load($schemaDn, $conn->_search($schemaDn, [ "suffix" => "", "attrs" => [ "ldapSyntaxes", "attributeTypes", "objectClasses", ], "scope" => "base", ])->first()); } if ($schema === null) { throw new IllegalAccessException("unable to find subschemaSubentry attribute"); } $parser = new LseSyntax(); $ldapSyntaxes = []; foreach ($schema->get("ldapSyntaxes", []) as $ldapSyntax) { $ldapSyntax = $parser->parse($ldapSyntax); $ldapSyntaxes[$ldapSyntax["oid"]] = $ldapSyntax; } $parser = new LseAttribute(); $attributeTypes = []; foreach ($schema->get("attributeTypes", []) as $attributeType) { $attributeType = $parser->parse($attributeType); $attributeTypes[$attributeType["oid"]] = $attributeType; } $parser = new LseObjectClass(); $objectClasses = []; foreach ($schema->get("objectClasses", []) as $objectClass) { $objectClass = $parser->parse($objectClass); $objectClasses[$objectClass["oid"]] = $objectClass; } return [ "ldap_syntaxes" => $this->ldapSyntaxes = $ldapSyntaxes, "attribute_types" => $this->attributeTypes = $attributeTypes, "object_classes" => $this->objectClasses = $objectClasses, ]; } protected $syntaxes; protected $attributes; protected $canonAttrs; protected $classes; protected $canonClasses; function init(): array { ## calculer la liste des syntaxes, et les classer par OID $ldapSyntaxes = $this->ldapSyntaxes; # rajouter une liste connue de syntaxes A::merge($ldapSyntaxes, consts::KNOWN_SLAPD_SYNTAXES); $syntaxes = []; foreach ($ldapSyntaxes as $syntax) { $oid = $syntax["oid"]; # si la syntaxe a déjà été définie, ignorer if (array_key_exists($oid, $syntaxes)) continue; $class = A::get(consts::KNOWN_SYNTAX_CLASSES, $oid); if ($class === null) { $binary = $syntax["x_not_human_readable"] || $syntax["x_binary_transfer_required"]; $class = $binary? BinarySyntax::class: StringSyntax::class; } $syntax["class"] = $class; $syntaxes[$oid] = $syntax; } ## calculer la liste des attributs, et les classer par nom canonique $attributes = []; $canonAttrs = []; foreach ($this->attributeTypes as $attribute) { $names = $attribute["names"]; $canonName = $names[0]; $attribute["name"] = $canonName; foreach ($names as $name) { $canonAttrs[strtolower($name)] = $canonName; } $attribute["class"] = A::_pget($syntaxes, [$attribute["syntax"], "class"]); $attributes[strtolower($canonName)] = $attribute; } # résoudre l'héritage des attributs foreach ($attributes as &$attribute) { foreach ($attribute["sups"] as $sup) { $sup = strtolower(A::get($canonAttrs, strtolower($sup), $sup)); A::update_n($attribute, $attributes[$sup]); } }; unset($attribute); # puis mettre à false les valeurs booléennes nulles foreach ($attributes as &$attribute) { foreach (LseAttribute::BOOL_ATTRS as $name) { $attribute[$name] = boolval($attribute[$name]); } }; unset($attribute); ## calculer la liste des classes, et les classer par nom canonique. ## les noms des attributs sont aussi canonisés $classes = []; $canonClasses = []; foreach ($this->objectClasses as $class) { $names = $class["names"]; $canonName = $names[0]; $class["name"] = $canonName; foreach ($names as $name) { $canonClasses[strtolower($name)] = $canonName; } $musts = A::with($class["musts"]); foreach ($musts as &$name) { $name = A::get($canonAttrs, strtolower($name), $name); }; unset($name); $class["musts"] = $musts; $mays = A::with($class["mays"]); foreach ($mays as &$name) { $name = A::get($canonAttrs, strtolower($name), $name); }; unset($name); $class["mays"] = $mays; $class["attrs"] = array_merge($musts, $mays); $classes[strtolower($canonName)] = $class; } # résoudre l'héritage des classes foreach ($classes as &$class) { foreach ($class["sups"] as $sup) { $sup = strtolower(A::get($canonAttrs, strtolower($sup), $sup)); $sup = $classes[$sup]; A::update_n($class, $sup); A::merge($class["musts"], $sup["musts"]); A::merge($class["mays"], $sup["mays"]); } }; unset($class); ## fin de l'initialisation return [ "syntaxes" => $this->syntaxes = $syntaxes, "attributes" => $this->attributes = $attributes, "canon_attrs" => $this->canonAttrs = $canonAttrs, "classes" => $this->classes = $classes, "canon_classes" => $this->canonClasses = $canonClasses, ]; } const getAttributes_overrides_SCHEMA = [ "name" => "string", "class" => "?string", "set" => "?int", "reset" => "?int", ]; /** @var Metadata */ private static $getAttributes_overrides_md; function getAttributes(array $objectClasses, ?array $overrides=null): array { if ($overrides !== null) { $tmp = []; foreach ($overrides as $name => $override) { $attribute = ValueException::check_nn( A::get($this->attributes, strtolower($name)) , "$name: attribut non défini"); $tmp[$attribute["name"]] = $override; } $overrides = $tmp; $md = md_utils::ensure_md(self::$getAttributes_overrides_md, self::getAttributes_overrides_SCHEMA); $md->eachEnsureSchema($overrides); } $nameRequired = []; foreach ($objectClasses as $name) { $name = A::get($this->canonClasses, strtolower($name), $name); $class = ValueException::check_nn( A::get($this->classes, strtolower($name)) , "$name: classe non définie"); foreach ($class["musts"] as $must) { $nameRequired[$must] = true; } foreach ($class["mays"] as $may) { A::replace_nx($nameRequired, $may, false); } } $attributes = [ "dn" => [ "name" => "dn", "class" => StringSyntax::class, "flags" => LdapAttr::MONOVALUED, ], ]; foreach ($nameRequired as $name => $required) { $lname = strtolower($name); $attribute = ValueException::check_nn( A::get($this->attributes, $lname) , "$name: attribut non défini"); $syntax = ValueException::check_nn( A::get($this->syntaxes, $attribute["syntax"]) , "$attribute[syntax]: syntaxe non définie"); $class = $attribute["class"]; $monovalued = $attribute["single_value"]? LdapAttr::MONOVALUED: 0; $binary = $syntax["x_binary_transfer_required"]? LdapAttr::BINARY: 0; $ordered = $attribute["x_ordered"]? LdapAttr::ORDERED: 0; $notHumanReadable = $syntax["x_not_human_readable"]? LdapAttr::NOT_HUMAN_READABLE: 0; $flags = $monovalued + $binary + $ordered + $notHumanReadable; $override = A::get($overrides, $name); if ($override !== null) { if ($override["class"] !== null) $class = $override["class"]; if ($override["set"] !== null) $flags = $flags | $override["set"]; if ($override["reset"] !== null) $flags = $flags & ~$override["reset"]; } $attributes[$lname] = [ "name" => $name, "class" => $class, "flags" => $flags, ]; } return $attributes; } }