Code

Updated schemaCheck
[gosa.git] / gosa-core / include / class_configRegistry.inc
1 <?php
3 class configRegistry{
5     public $config = NULL;
6     public $properties = array();
7     public $ldapStoredProperties = array(); 
8     public $fileStoredProperties = array(); 
9     public $classToName = array(); 
11     public $status = 'none';
13     // Excludes property values defined in ldap 
14     public $ignoreLdapProperties = FALSE;
16     // Contains all classes with plInfo
17     public $classesWithInfo = array();
18     public $pluginRequirements  = array();
19     public $categoryToClass  = array();
21     public $objectClasses = array();
23     public $detectedSchemaIssues = array();
24     public $schemaCheckFailed = FALSE;
25     public $schemaCheckFinished = FALSE;
27     function __construct($config)
28     {
29         $this->config = &$config;
31         // Detect classes that have a plInfo method 
32         global $class_mapping;
33         foreach ($class_mapping as $cname => $path){
34             $cmethods = get_class_methods($cname);
35             if (is_array($cmethods) && in_array_ics('plInfo',$cmethods)){
37                 // Get plugin definitions
38                 $def = call_user_func(array($cname, 'plInfo'));;
40                 // Register Post Events (postmodfiy,postcreate,postremove,checkhook)
41                 if(count($def)){
42                     $this->classesWithInfo[$cname] = $def;
43                 }
44             }
45         }
47         // (Re)Load properties
48         $this->reload();
49     }
52     function validateSchemata($force = FALSE, $disableIncompatiblePlugins = FALSE)
53     {
54         // We can check the schemata only with a valid LDAP connection
55         if(empty($this->config->current['CONFIG'])){
56             return(TRUE); 
57         }
59         // Don't do things twice unless forced
60         if($this->schemaCheckFinished && !$force) return($this->schemaCheckFailed); 
62         // Prepare result array
63         $this->detectedSchemaIssues = array();
64         $this->detectedSchemaIssues['missing'] = array();
65         $this->detectedSchemaIssues['versionMismatch'] = array();
67         // Read objectClasses from ldap
68         if(!count($this->objectClasses)){
69             $ldap = $this->config->get_ldap_link();
70             $ldap->cd($this->config->current['BASE']);
71             $this->objectClasses = $ldap->get_objectclasses();
72         }
74         // Collect required schema infos
75         $this->pluginRequirements = array('ldapSchema' => array());
76         $this->categoryToClass = array();
77         foreach($this->classesWithInfo as $cname => $defs){
78             if(isset($defs['plRequirements']['ldapSchema'])){
79                 $this->pluginRequirements['ldapSchema'][$cname] = $defs['plRequirements']['ldapSchema'];
80             }
81         }
83         // Check schema requirements now        $missing = $invalid = array();
84         foreach($this->pluginRequirements['ldapSchema'] as $cname => $requirements){
85             foreach($requirements as $oc => $version){
86                 if(1 || !$this->ocAvailable($oc)){
87                     $this->detectedSchemaIssues['missing'][] = $oc;
88                     $this->schemaCheckFailed = TRUE;
89                 }elseif(!empty($version)){
90                     $currentVersion = $this->getObjectClassVersion($oc);
91                     if(!empty($currentVersion) && !$this->ocVersionMatch($version, $currentVersion)){
92                         if($currentVersion == -1){
93                             $currentVersion = _("unknown");
94                         }
95                         $this->detectedSchemaIssues['versionMismatch'] = 
96                             sprintf(_("%s has version %s but %s required!"), bold($oc),bold($currentVersion),bold($version));
97                         $this->schemaCheckFailed = TRUE;
98                     }
99                 }
100             }
101         }
102         $this->schemaCheckFinished =TRUE;
103         return(!$this->schemaCheckFailed);
104     }
106         
107     function displayErrors()
108     {
109         if(count($this->detectedSchemaIssues['missing'])){
110             msg_dialog::display(_("Schema validation error"), 
111                     _("The following objectClasses are missing:").
112                     "<div class='scrollContainer' style='height:100px'>".
113                     msgPool::buildList($this->detectedSchemaIssues['missing']).
114                     "</div>",
115                     ERROR_DIALOG);
116         }    
117         if(count($this->detectedSchemaIssues['versionMismatch'])){
118             msg_dialog::display(_("Schema validation error"), 
119                     _("The following objectClasses do not match the version requirements:").
120                     "<div class='scrollContainer' style='height:100px'>".
121                     msgPool::buildList($this->detectedSchemaIssues['versionMismatch']).
122                     "</div>",
123                     ERROR_DIALOG);
124         }    
125     }
128     function ocVersionMatch($required, $installed)
129     {
130         $operator = preg_replace('/^([=<>]*).*$/',"\\1",$required);
131         $required = preg_replace('/^[=<>]*(.*)$/',"\\1",$required);
132         return(version_compare($installed,$required, $operator)); 
133     }
135     
136     function getObjectClassVersion($oc)
137     {
138         if(!isset($this->objectClasses[$oc])){
139             return(NULL);
140         }else{
141             $version = -1; // unknown
142             if(preg_match("/(v[^)]*)/", $this->objectClasses[$oc]['DESC'])){
143                 $version = preg_replace('/^.*\(v([^)]*)\).*$/',"\\1", $this->objectClasses[$oc]['DESC']);
144             }
145         }
146         return($version);
147     }
148     
150     // check wheter an objectClass is installed or not.
151     function ocAvailable($name)
152     {
153         return(isset($this->objectClasses[$name]));
154     }
157     function reload($force = FALSE)
158     {
159         // Do not reload the properties everytime, once we have  
160         //  everything loaded and registrered skip the reload.
161         // Status is 'finished' once we had a ldap connection (logged in)
162         if(!$force && $this->status == 'finished') return;
164         // Reset everything
165         $this->ldapStoredProperties = array();
166         $this->fileStoredProperties = array();
167         $this->properties = array();
168         $this->mapByName = array();
170         // Search for config flags defined in the config file (TAB section)
171         foreach($this->config->data['TABS'] as $tabname => $tabdefs){
172             foreach($tabdefs as $info){
174                 // Check if the info is valid
175                 if(isset($info['NAME']) && isset($info['CLASS'])){
177                     // Check if there is nore than just the plugin definition
178                     if(count($info) > 2){
179                         foreach($info as $name => $value){
180                             
181                             if(!in_array($name, array('CLASS','NAME'))){
182                                 $class= $info['CLASS'];    
183                                 $this->fileStoredProperties[$class][strtolower($name)] = $value;
184                             }
185                         }
186                     }
187                 }
188             }
189         }
191         // Search for config flags defined in the config file (MENU section)
192         foreach($this->config->data['MENU'] as $section => $entries){
193             foreach($entries as $entry){
194                 if(count($entry) > 2 && isset($entry['CLASS'])){
195                     $class = $entry['CLASS'];
196                     foreach($entry as $name => $value){
197                         if(!in_array($name, array('CLASS','ACL'))){
198                             $this->fileStoredProperties[strtolower($class)][strtolower($name)] = $value;
199                         }
200                     }
201                 }
202             }
203         }
205         // Search for config flags defined in the config file (MAIN section)
206         foreach($this->config->data['MAIN'] as $name => $value){
207             $this->fileStoredProperties['core'][strtolower($name)] = $value;
208         }
210         // Search for config flags defined in the config file (Current LOCATION section)
211         if(isset($this->config->current)){
212             foreach($this->config->current as $name => $value){
213                 $this->fileStoredProperties['core'][strtolower($name)] = $value;
214             }
215         }
217         // Skip searching for LDAP defined properties if 'ignoreLdapProperties' is set to 'true'
218         //  in the config. 
219         $this->ignoreLdapProperties = FALSE;
220         if(isset($this->fileStoredProperties['core'][strtolower('ignoreLdapProperties')]) && 
221             preg_match("/(true|on)/i", $this->fileStoredProperties['core'][strtolower('ignoreLdapProperties')])){
222             $this->ignoreLdapProperties = TRUE;
223         }
225         // Search for all config flags defined in the LDAP - BUT only if we ARE logged in. 
226         if(!empty($this->config->current['CONFIG'])){
227             $ldap = $this->config->get_ldap_link();
228             $ldap->cd($this->config->current['CONFIG']);
229             $ldap->search('(&(objectClass=gosaConfig)(gosaSetting=*))', array('cn','gosaSetting'));
230             while($attrs = $ldap->fetch()){
231                 $class = $attrs['cn'][0];
232                 for($i=0; $i<$attrs['gosaSetting']['count']; $i++){
233                     list($name,$value) = preg_split("/:/",$attrs['gosaSetting'][$i],2);
234                     $this->ldapStoredProperties[$class][$name] = $value;
235                 }
236             }
237             $this->status = 'finished';
238         }
240         // Register plugin properties.
241         foreach ($this->classesWithInfo as $cname => $def){
243             // Detect class name
244             $name = $cname;
245             $name = (isset($def['plShortName'])) ? $def['plShortName'] : $cname;
246             $name = (isset($def['plDescription'])) ? $def['plDescription'] : $cname;
248             // Register post events
249             $this->classToName[$cname] = $name;
250             $data = array('name' => 'postcreate','type' => 'command');
251             $this->register($cname, $data);    
252             $data = array('name' => 'postremove','type' => 'command');
253             $this->register($cname, $data);    
254             $data = array('name' => 'postmodify','type' => 'command');
255             $this->register($cname, $data);    
256             $data = array('name' => 'check', 'type' => 'command');
257             $this->register($cname, $data);    
259             // Register properties 
260             if(isset($def['plProperties'])){
261                 foreach($def['plProperties'] as $property){
262                     $this->register($cname, $property);
263                 }
264             }
265         }
266     }
268     function register($class,$data)
269     {
270         $id = count($this->properties);
271         $this->properties[$id] = new gosaProperty($this,$class,$data);
272         $p = strtolower("{$class}::{$data['name']}");
273         $this->mapByName[$p] = $id;
274     }
276     public function getAllProperties()
277     {
278         return($this->properties);
279     }
281     function propertyExists($class,$name)
282     {       
283         $p = strtolower("{$class}::{$name}");
284         return(isset($this->mapByName[$p]));
285     }
287     private function getId($class,$name)
288     {
289         $p = strtolower("{$class}::{$name}");
290         if(!isset($this->mapByName[$p])){
291             return(-1);
292         }       
293         return($this->mapByName[$p]);    
294     }
296     function getProperty($class,$name)
297     {
298         if($this->propertyExists($class,$name)){
299             return($this->properties[$this->getId($class,$name)]);
300         }
301         return(NULL); 
302     }
304     function getPropertyValue($class,$name)
305     {   
306         if($this->propertyExists($class,$name)){
307             $tmp = $this->getProperty($class,$name);
308             return($tmp->getValue());
309         }
310         return("");
311     }
313     function setPropertyValue($class,$name, $value)
314     {   
315         if($this->propertyExists($class,$name)){
316             $tmp = $this->getProperty($class,$name);
317             return($tmp->setValue($value));
318         }
319         return("");
320     }
322     function saveChanges()
323     {
324         $migrate = array();
325         foreach($this->properties as $prop){
327             // Is this property modified
328             if(in_array($prop->getStatus(),array('modified','removed'))){
330                 // Check if we've to migrate something before we can make the changes effective. 
331                 if($prop->migrationRequired()){
332                     $migrate[] = $prop;
333                 }else{
334                     $prop->save();
335                 }
336             }
337         }
338         return($migrate);
339     }
343 class gosaProperty
345     protected $name = "";
346     protected $class = "";
347     protected $value = "";
348     protected $tmp_value = "";  // Used when modified but not saved 
349     protected $type = "string";
350     protected $default = "";
351     protected $defaults = "";
352     protected $description = "";
353     protected $check = "";
354     protected $migrate = "";
355     protected $mandatory = FALSE;
356     protected $group = "default";
357     protected $parent = NULL;
358     protected $data = array();
360     protected $migrationClass = NULL;
362     /*!  The current property status
363      *     'ldap'       Property is stored in ldap 
364      *     'file'       Property is stored in the config file
365      *     'undefined'  Property is currently not stored anywhere
366      *     'modified'   Property has been modified (should be saved)
367      */
368     protected $status = 'undefined';
370     protected $attributes = array('name','type','default','description','check',
371             'migrate','mandatory','group','defaults');
376     function __construct($parent,$classname,$data)
377     {
378         // Set some basic infos 
379         $this->parent = &$parent;
380         $this->class = $classname;
381         $this->data  = $data;
383         // Get all relevant information from the data array (comes from plInfo)    
384         foreach($this->attributes as $aName){
385             if(isset($data[$aName])){
386                 $this->$aName = $data[$aName];
387             }
388         }      
390         // Initialize with the current value
391         $this->_restoreCurrentValue(); 
393     }
395     function migrationRequired()
396     {
397         // Instantiate migration class 
398         if(!empty($this->migrate) && $this->migrationClass == NULL){
399             if(!class_available($this->migrate)){
400                 trigger_error("Cannot start migration for gosaProperty::'{$this->getName()}' class not found ({$this->migrate})!");
401             }else{
402                 $class = $this->migrate;
403                 $tmp = new $class($this->parent->config,$this);
404                 if(! $tmp instanceof propertyMigration){ 
405                     trigger_error("Cannot start migration for gosaProperty::'{$this->getName()}' doesn't implement propertyMigration!");
406                 }else{
407                     $this->migrationClass = $tmp;
408                 }
409             }
410         }
411         if(empty($this->migrate) || $this->migrationClass == NULL){
412             return(FALSE);
413         }
414         return($this->migrationClass->checkForIssues());
415     }
417     function getMigrationClass()
418     {
419         return($this->migrationClass);
420     }
422     function check()
423     {
424         $val = $this->getValue(TRUE);
425         $return = TRUE;
426         if($this->mandatory && empty($val)){
427             $return = FALSE;
428         }
430         $check = $this->getCheck();
431         if(!empty($val) && !empty($check)){
432             $res = call_user_func(preg_split("/::/", $this->check),$messages=TRUE, $this->class,$this->name,$val, $this->type);
433             if(!$res){
434                 $return = FALSE;
435             }
436         }
437         return($return);
438     }
440     static function isBool($message,$class,$name,$value, $type)
441     {
442         $match = in_array($value,array('true','false',''));
444         // Display the reason for failing this check.         
445         if($message && ! $match){
446             msg_dialog::display(_("Warning"), 
447                     sprintf(_("The value '%s' specified for '%s:%s' is invalid. A bool value is required here!"), 
448                         bold($value),bold($class),bold($name)), 
449                     WARNING_DIALOG);
450         }
451     
452         return($match);
453     }
455     static function isString($message,$class,$name,$value, $type)
456     {
457         $match = TRUE;
458     
459         // Display the reason for failing this check.         
460         if($message && ! $match){
461             msg_dialog::display(_("Warning"), 
462                     sprintf(_("The value '%s' specified for '%s:%s' is invalid. A string value is required here!"), 
463                         bold($value),bold($class),bold($name)), 
464                     WARNING_DIALOG);
465         }
467         return($match);
468     }
470     static function isInteger($message,$class,$name,$value, $type)
471     {
472         $match = is_numeric($value) && !preg_match("/[^0-9]/", $value);
474         // Display the reason for failing this check.         
475         if($message && ! $match){
476             msg_dialog::display(_("Warning"), 
477                     sprintf(_("The value '%s' specified for '%s:%s' is invalid. A numeric value is required here!"), 
478                         bold($value),bold($class),bold($name)), 
479                     WARNING_DIALOG);
480         }
482         return($match);
483     }
485     static function isPath($message,$class,$name,$value, $type)
486     {
487         $match = preg_match("#^(/[^/]*/){1}#", $value);
488     
489         // Display the reason for failing this check.         
490         if($message && ! $match){
491             msg_dialog::display(_("Warning"), 
492                     sprintf(_("The path '%s' specified for '%s:%s' is invalid!"), 
493                         bold($value),bold($class),bold($name)), 
494                     WARNING_DIALOG);
495         }
497         return($match);
498     }
500     static function isReadablePath($message,$class,$name,$value, $type)
501     {
502         $match = !empty($value)&&is_dir($value)&&is_writeable($value);
503    
504         // Display the reason for failing this check.         
505         if($message && ! $match){
506             if(!is_dir($value)){
507                 msg_dialog::display(_("Warning"), 
508                         sprintf(_("The folder '%s' specified for '%s:%s' does not exists!"), 
509                             bold($value),bold($class),bold($name)), 
510                         WARNING_DIALOG);
511             }elseif(!is_readable($value)){
512                 msg_dialog::display(_("Warning"), 
513                         sprintf(_("The folder '%s' specified for '%s:%s' cannot be used for reading!"), 
514                             bold($value),bold($class),bold($name)), 
515                         WARNING_DIALOG);
516             }
517         }
519         return($match);
520     }
522     static function isWriteablePath($message,$class,$name,$value, $type)
523     {
524         $match = !empty($value)&&is_dir($value)&&is_writeable($value);
525    
526         // Display the reason for failing this check.         
527         if($message && ! $match){
528             if(!is_dir($value)){
529                 msg_dialog::display(_("Warning"), 
530                         sprintf(_("The folder '%s' specified for '%s:%s' does not exists!"), 
531                             bold($value),bold($class),bold($name)), 
532                         WARNING_DIALOG);
533             }elseif(!is_writeable($value)){
534                 msg_dialog::display(_("Warning"), 
535                         sprintf(_("The folder '%s' specified for '%s:%s' cannot be used for writing!"), 
536                             bold($value),bold($class),bold($name)), 
537                         WARNING_DIALOG);
538             }
539         }
541         return($match);
542     }
544     static function isReadableFile($message,$class,$name,$value, $type)
545     {
546         $match = !empty($value) && is_readable($value) && is_file($value);
548         // Display the reason for failing this check.         
549         if($message && ! $match){
550                 
551             if(!is_file($value)){
552                 msg_dialog::display(_("Warning"), 
553                         sprintf(_("The file '%s' specified for '%s:%s' does not exists!"), 
554                             bold($value),bold($class),bold($name)), 
555                         WARNING_DIALOG);
556             }elseif(!is_readable($value)){
557                 msg_dialog::display(_("Warning"), 
558                         sprintf(_("The file '%s' specified for '%s:%s' cannot be read!"), 
559                             bold($value),bold($class),bold($name)), 
560                         WARNING_DIALOG);
561             }
562         }
564         return($match);
565     }
567     static function isCommand($message,$class,$name,$value, $type)
568     {
569         $match = TRUE;
571         // Display the reason for failing this check.         
572         if($message && ! $match){
573             msg_dialog::display(_("Warning"), 
574                     sprintf(_("The command '%s' specified for '%s:%s' is invalid!"), 
575                         bold($value),bold($class),bold($name)), 
576                     WARNING_DIALOG);
577         }
578         
579         return($match);
580     }
582     static function isDn($message,$class,$name,$value, $type)
583     {
584         $match = preg_match("/^([a-z]*=[^=,]*,)*[^=]*=[^=]*$/i", $value);
586         // Display the reason for failing this check.         
587         if($message && ! $match){
588             msg_dialog::display(_("Warning"), 
589                     sprintf(_("The dn '%s' specified for '%s:%s' is invalid!"), 
590                         bold($value),bold($class),bold($name)), 
591                     WARNING_DIALOG);
592         }
593         
594         return($match);
595     }
597     static function isRdn($message,$class,$name,$value, $type)
598     {
599         $match = preg_match("/^([a-z]*=[^=,]*,)*[^=]*=[^=,]*,?$/i", $value);
601         // Display the reason for failing this check.         
602         if($message && ! $match){
603             msg_dialog::display(_("Warning"), 
604                     sprintf(_("The rdn '%s' specified for '%s:%s' is invalid!"), 
605                         bold($value),bold($class),bold($name)), 
606                     WARNING_DIALOG);
607         }
608         
609         return($match);
610     }
612     private function _restoreCurrentValue()
613     {
614         // First check for values in the LDAP Database.
615         if(isset($this->parent->ldapStoredProperties[$this->class][$this->name])){
616             $this->setStatus('ldap');
617             $this->value = $this->parent->ldapStoredProperties[$this->class][$this->name];
618             return;
619         }
621         // Second check for values in the config file.
622         if(isset($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)])){
623             $this->setStatus('file');
624             $this->value = $this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)];
625             return;
626         }
628         // If there still wasn't found anything then fallback to the default.
629         if($this->getStatus() == 'undefined'){
630             $this->value = $this->getDefault();
631         }
632     }
634     function getMigrate() { return($this->migrate); }
635     function getCheck() { return($this->check); }
636     function getName() { return($this->name); }
637     function getClass() { return($this->class); }
638     function getGroup() { return($this->group); }
639     function getType() { return($this->type); }
640     function getDescription() { return($this->description); }
641     function getDefault() { return($this->default); }
642     function getDefaults() { return($this->defaults); }
643     function getStatus() { return($this->status); }
644     function isMandatory() { return($this->mandatory); }
646     function setValue($str) 
647     {
648         if(in_array($this->getStatus(), array('modified'))){
649             $this->tmp_value = $str; 
650         }elseif($this->value != $str){
651             $this->setStatus('modified'); 
652             $this->tmp_value = $str; 
653         }
654     }
656     function getValue($temporary = FALSE) 
657     { 
658         if($temporary){
659             if(in_array($this->getStatus(), array('modified','removed'))){
660                 return($this->tmp_value); 
661             }else{
662                 return($this->value); 
663             }
664         }else{ 
666             // Do not return ldap values if we've to ignore them.
667             if($this->parent->ignoreLdapProperties){
668                 if(isset($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)])){
669                     return($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)]);
670                 }else{
671                     return($this->getDefault());
672                 }
673             }else{
674                 return($this->value); 
675             }
676         }
677     }
679     function restoreDefault() 
680     {
681         if(in_array($this->getStatus(),array('ldap'))){
682             $this->setStatus('removed'); 
684             // Second check for values in the config file.
685             if(isset($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)])){
686                 $this->tmp_value = $this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)];
687             }else{
688                 $this->tmp_value = $this->getDefault();
689             }
690         }
691     }
693     function save()
694     {
695         if($this->getStatus() == 'modified'){
696             $ldap = $this->parent->config->get_ldap_link();
697             $ldap->cd($this->parent->config->current['BASE']);
698             $dn = "cn={$this->class},".$this->parent->config->current['CONFIG'];
699             $ldap->cat($dn);
700             if(!$ldap->count()){
701                 $ldap->cd($dn);
702                 $data = array(
703                         'cn' => $this->class, 
704                         'objectClass' => array('top','gosaConfig'),
705                         'gosaSetting' => $this->name.":".$this->tmp_value);
707                 $ldap->add($data);
708                 if(!$ldap->success()){
709                     echo $ldap->get_error();
710                 }
712             }else{
713                 $attrs = $ldap->fetch();
714                 $data = array();
715                 $found = false;
716                 if(isset($attrs['gosaSetting']['count'])){
717                     for($i = 0;$i<$attrs['gosaSetting']['count']; $i ++){
718                         $set = $attrs['gosaSetting'][$i];
719                         if(preg_match("/^{$this->name}:/", $set)){
720                             $set = "{$this->name}:{$this->tmp_value}";
721                             $found = true;
722                         }
723                         $data['gosaSetting'][] = $set;
724                     }
725                 }
726                 if(!$found) $data['gosaSetting'][] = "{$this->name}:{$this->tmp_value}";
727                 $ldap->cd($dn);
728                 $ldap->modify($data);
729                 if(!$ldap->success()){
730                     echo $ldap->get_error();
731                 }
732             }
733             $this->value = $this->tmp_value;
734             $this->setStatus('ldap'); 
735         }elseif($this->getStatus() == 'removed'){
736             $ldap = $this->parent->config->get_ldap_link();
737             $ldap->cd($this->parent->config->current['BASE']);
738             $dn = "cn={$this->class},".$this->parent->config->current['CONFIG'];
739             $ldap->cat($dn);
740             $attrs = $ldap->fetch();
741             $data = array('gosaSetting' => array());
742             for($i = 0;$i<$attrs['gosaSetting']['count']; $i ++){
743                 $set = $attrs['gosaSetting'][$i];
744                 if(preg_match("/^{$this->name}:/", $set)){
745                     continue;
746                 }
747                 $data['gosaSetting'][] = $set;
748             }
749             $ldap->cd($dn);
750             $ldap->modify($data);
751             if(!$ldap->success()){
752                 echo $ldap->get_error();
753             }
754             $this->_restoreCurrentValue();
755         }
756     }
758     private function setStatus($state) 
759     {
760         if(!in_array($state, array('ldap','file','undefined','modified','removed'))) {
761             trigger_error("Unknown property status given '{$state}' for {$this->class}:{$this->name}!");
762         }else{
763             $this->status = $state; 
764         }
765     }
767     function isValid() 
768     { 
769         return(TRUE);    
770     }
775 interface propertyMigration
777     function __construct($config,$property);
781 ?>