226 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			226 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| namespace nur\ldap;
 | |
| 
 | |
| use ArrayAccess;
 | |
| use Countable;
 | |
| use Iterator;
 | |
| use nur\A;
 | |
| use nur\b\coll\TIterableArray;
 | |
| use nur\ldap\syntaxes\AbstractSyntax;
 | |
| use nur\str;
 | |
| 
 | |
| class LdapAttr implements ArrayAccess, Countable, Iterator {
 | |
|   use TIterableArray;
 | |
| 
 | |
|   const MONOVALUED = 1, BINARY = 2, ORDERED = 4, NOT_HUMAN_READABLE = 8;
 | |
| 
 | |
|   function __construct(string $name, ?array &$values, ?AbstractSyntax $syntax, ?int $flags) {
 | |
|     $this->name = $name;
 | |
|     $this->syntax = $syntax;
 | |
|     $this->flags = $flags;
 | |
|     $this->reset($values);
 | |
|   }
 | |
| 
 | |
|   /** @var string */
 | |
|   protected $name;
 | |
| 
 | |
|   function name(): string {
 | |
|     return $this->name;
 | |
|   }
 | |
| 
 | |
|   /** @var ?array */
 | |
|   protected $data;
 | |
| 
 | |
|   function reset(?array &$values): self {
 | |
|     $this->data =& $values;
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   /** @var AbstractSyntax */
 | |
|   protected $syntax;
 | |
| 
 | |
|   /** @var int */
 | |
|   protected $flags;
 | |
| 
 | |
|   function isMonovalued(): bool {
 | |
|     return $this->flags !== null && $this->flags & self::MONOVALUED != 0;
 | |
|   }
 | |
| 
 | |
|   function isBinary(): bool {
 | |
|     return $this->flags !== null && $this->flags & self::BINARY != 0;
 | |
|   }
 | |
| 
 | |
|   function isOrdered(): bool {
 | |
|     return $this->flags !== null && $this->flags & self::ORDERED != 0;
 | |
|   }
 | |
| 
 | |
|   function isNotHumanReadable(): bool {
 | |
|     return $this->flags !== null && $this->flags & self::NOT_HUMAN_READABLE != 0;
 | |
|   }
 | |
| 
 | |
|   protected function fromLdap($value) {
 | |
|     $syntax = $this->syntax;
 | |
|     if ($syntax !== null) {
 | |
|       if ($this->isMonovalued()) $value = $syntax->fromMonovaluedLdap($value);
 | |
|       else $value = $syntax->fromMultivaluedLdap($value);
 | |
|     }
 | |
|     return $value;
 | |
|   }
 | |
|   protected function fromPhp($value): ?iterable {
 | |
|     $syntax = $this->syntax;
 | |
|     if ($syntax !== null) $value = $syntax->fromPhp($value);
 | |
|     else A::ensure_narray($value);
 | |
|     return $value;
 | |
|   }
 | |
| 
 | |
|   /** retourner un tableau si multivalué, une valeur scalaire si monovalué */
 | |
|   function get($index=null) {
 | |
|     $value = $this->fromLdap($this->data);
 | |
|     if ($index !== null && is_array($value)) {
 | |
|       $value = array_key_exists($index, $value)? $value[$index]: null;
 | |
|     }
 | |
|     return $value;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * retourner toutes les valeurs
 | |
|    *
 | |
|    * @param string $checkPrefixDel ne retourner que les valeurs qui commencent
 | |
|    * par ce préfixe ET enlever le préfixe
 | |
|    */
 | |
|   function all(?string $checkPrefixDel=null): ?array {
 | |
|     if ($this->syntax === null) $values = $this->data;
 | |
|     else $values = $this->syntax->fromMultivaluedLdap($this->data);
 | |
|     if ($checkPrefixDel !== null && $values !== null) {
 | |
|       $filtered = [];
 | |
|       foreach ($values as $value) {
 | |
|         if (str::del_prefix($value, $checkPrefixDel)) {
 | |
|           $filtered[] = $value;
 | |
|         }
 | |
|       }
 | |
|       $values = $filtered;
 | |
|     }
 | |
|     return $values;
 | |
|   }
 | |
| 
 | |
|   /** retourner la première valeur */
 | |
|   function first(?string $checkPrefixDel=null) {
 | |
|     return A::first($this->all($checkPrefixDel));
 | |
|   }
 | |
| 
 | |
|   function set($values, bool $unlessNn=false): self {
 | |
|     if ($values instanceof LdapAttr) $values = $values->array();
 | |
|     if (!$unlessNn || $this->data === null) {
 | |
|       $this->data = $this->fromPhp($values);
 | |
|     }
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   protected static function in_array(string $needle, array $haystack, bool $strict, ?int &$index=null): bool {
 | |
|     if (!$strict) $needle = strtolower($needle);
 | |
|     foreach ($haystack as $index => $hay) {
 | |
|       if ($strict && $hay === $needle) return true;
 | |
|       if (!$strict && strtolower($hay) == $needle) return true;
 | |
|     }
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   /** vérifier si la valeur spécifiée figure dans l'attribut */
 | |
|   function contains($value, bool $strict=false): bool {
 | |
|     $value = A::first($this->fromPhp($value));
 | |
|     if ($value === null || $this->data === null) return false;
 | |
|     return self::in_array($value, $this->data, $strict);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * l'unicité est calculée ainsi:
 | |
|    * - en mode strict, ce doit être une égalité parfaite
 | |
|    * - en mode non strict, la comparaison est insensible à la casse
 | |
|    * XXX à terme, implémenter la comparaison en fonction de la syntaxe
 | |
|    */
 | |
|   function add($value, bool $unique=true, bool $strict=false): self {
 | |
|     $value = A::first($this->fromPhp($value));
 | |
|     if ($value !== null) {
 | |
|       if (!$unique || $this->data === null ||
 | |
|         !self::in_array($value, $this->data, $strict)) {
 | |
|         $this->data[] = $value;
 | |
|       }
 | |
|     }
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   function addAll(?iterable $values): self {
 | |
|     if ($values !== null) {
 | |
|       foreach ($values as $value) {
 | |
|         $this->add($value);
 | |
|       }
 | |
|     }
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   function del($value, int $maxCount=-1, bool $strict=false): self {
 | |
|     if ($value !== null && $this->data !== null) {
 | |
|       $value = A::first($this->fromPhp($value));
 | |
|       $rekey = false;
 | |
|       while ($maxCount != 0) {
 | |
|         if (!self::in_array($value, $this->data, $strict, $index)) break;
 | |
|         unset($this->data[$index]);
 | |
|         $rekey = true;
 | |
|         if ($maxCount > 0) $maxCount--;
 | |
|       }
 | |
|       if ($rekey) $this->data = array_values($this->data);
 | |
|     }
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   function ins(int $index, $value): self {
 | |
|     $value = A::first($this->fromPhp($value));
 | |
|     if ($value !== null) {
 | |
|       A::insert($this->data, $index, $value);
 | |
|     }
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   function unset(int $index): self {
 | |
|     if ($this->data !== null) {
 | |
|       $count = count($this->array());
 | |
|       if ($count > 0 && $index < 0) {
 | |
|         while ($index < 0) $index += $count;
 | |
|       }
 | |
|       unset($this->data[$index]);
 | |
|       $this->data = array_values($this->data);
 | |
|     }
 | |
|     return $this;
 | |
|   }
 | |
| 
 | |
|   function key() { return $this->_key(); }
 | |
|   function current() {
 | |
|     $current = $this->_current();
 | |
|     $syntax = $this->syntax;
 | |
|     if ($syntax !== null) $current = $syntax->ldap2php($current);
 | |
|     return $current;
 | |
|   }
 | |
| 
 | |
|   #############################################################################
 | |
|   # données au format LDAP
 | |
| 
 | |
|   function __toString() {
 | |
|     return implode("\n", $this->data);
 | |
|   }
 | |
|   /** retourner les données au format LDAP */
 | |
|   function &array(): ?array { return $this->data; }
 | |
|   function count(): int { return count($this->data); }
 | |
|   function keys(): array { return array_keys($this->data); }
 | |
|   function offsetExists($key) {
 | |
|     return $this->data !== null && array_key_exists($key, $this->data);
 | |
|   }
 | |
|   function offsetGet($key) { return array_key_exists($key, $this->data)? $this->data[$key]: null; }
 | |
|   function offsetSet($key, $value) { $this->data[$key] = $value; }
 | |
|   function offsetUnset($key) { unset($this->data[$key]); }
 | |
| 
 | |
|   function __isset($key) { return $this->offsetExists($key); }
 | |
|   function __get($key) { return $this->offsetGet($key); }
 | |
|   function __set($key, $value) { $this->offsetSet($key, $value); }
 | |
|   function __unset($key) { $this->offsetUnset($key); }
 | |
| }
 |