diff Lib/Form/Container.pm @ 0:03e58a454b20

Создан репозитарий
author Sergey
date Tue, 14 Jul 2009 12:54:37 +0400
parents
children 16ada169ca75
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Lib/Form/Container.pm	Tue Jul 14 12:54:37 2009 +0400
@@ -0,0 +1,170 @@
+package Form::Container;
+use strict;
+use Common;
+use Form::Filter;
+use base qw(Form::Item);
+
+BEGIN {
+    DeclareProperty Schema => ACCESS_READ;
+    DeclareProperty Children => ACCESS_READ;
+}
+
+sub CTOR {
+    my ($this,%args) = @_;
+    $args{Schema} or die new Exception('A schema is required');
+    
+    $this->SUPER::CTOR(@args{qw(Id Form Parent Attributes)});
+    $this->{$Schema} = $args{Schema};
+}
+
+sub ResolveItem {
+    my ($this,$ItemId) = @_;
+    
+    if (my $schemaChild = $this->{$Schema}->FindChild($ItemId->Name)) {
+        if ($schemaChild->isMulti) {
+            defined $ItemId->InstanceID or die new Exception('Instance id is required for a muti element');
+            if (my $child = $this->{$Children}{$ItemId->Name}[$ItemId->InstanceID]){
+                return $child;
+            } else {
+                return undef if not $this->Form->AutoCreate;
+                return $this->{$Children}{$ItemId->Name}[$ItemId->InstanceID] = $this->Form->CreateInstance($schemaChild,$ItemId,$this);
+            }
+            
+        } else {
+            defined $ItemId->InstanceID and die new Exception('The child is a single element',$this->Id->Canonical,$ItemId->Name);
+            if(my $child = $this->{$Children}{$ItemId->Name}) {
+                return $child;
+            } else {
+                return undef if not $this->Form->AutoCreate;
+                return $this->{$Children}{$ItemId->Name} = $this->Form->CreateInstance($schemaChild,$ItemId,$this);
+            }
+        }
+    } else {
+        die new Exception('The requested item isn\'t exists in the schema', $this->Id->Canonical,$ItemId->Name);
+    }
+}
+
+sub isEmpty {
+    my ($this) = @_;
+
+    foreach my $child (values %{$this->{$Children} || {} }) {
+        if (ref $child eq 'ARRAY') {
+            foreach my $inst (@$child) {
+                return 0 if not $child->isEmpty;
+            }
+        } else {
+            return 0 if not $child->isEmpty;
+        }
+    }
+
+    return 1;
+}
+
+=pod
+Ïîëó÷àåò äî÷åðíèå êîíòåíåðû â âèäå ñïèñêà, ïðè òîì òîëüêî íå ïóñòûå êîíòåéíåðû.
+Åñëè äî÷åðííèé êîíòåéíåð íå ìíîæåñòâåííûé, òî ñïèñîê áóäåò ñîñòîÿòü èç îäíîãî ýëåìåíòà.
+=cut
+sub GetChild {
+    my ($this,$name) = @_;
+    return unless exists $this->{$Children}{$name};
+    return( grep $_, map { UNIVERSAL::isa($_,'ARRAY') ? @{$_} : $_ } $this->{$Children}{$name} );
+}
+
+=pod
+Âûïîëíÿåò ôèëüòðû ïî ñõåìå äëÿ ñåáÿ è âñåõ äåòåé.
+Ôèëüòðû îïðåäåëÿþòñÿ ïî ñõåìå è âûçûâàþòñÿ â ðàçëè÷íõ êîíòåêñòàõ
+
+* ñíà÷àëà äëÿ ãðóïïû,
+* ïîòîì äëÿ äåòèøåê, ïðè÷åì åñëè
+    * äåòèøêè ìíîæåñòâåííûå, òî
+        * ñíñ÷àëà äëÿ íàáîðà äåòèøåê, à ïîòîì
+        * äëÿ êàæäîãî â îòäåëüíîñòè
+=cut
+sub Validate {
+    my ($this,$rhDisableFilters) = @_;
+    
+    $rhDisableFilters ||= {};
+
+    my @errors;
+
+    foreach my $filter (grep {$_->SUPPORTED_CONTEXT & (Form::Filter::CTX_SINGLE) and not exists $rhDisableFilters->{$_}} map {$_->Instance} $this->{$Schema}->Filters) {
+        my $result = $filter->Invoke($this,Form::Filter::CTX_SINGLE | Form::Filter::CTX_EXISTENT,$this->{$Schema});
+        if ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
+            return ();
+        } elsif ($result->State == Form::FilterResult::STATE_ERROR) {
+            push @errors,$result;
+        }
+    }
+
+    CHILD_LOOP: foreach my $schemaChild ($this->{$Schema}->Children) {
+        
+        if ($schemaChild->isMulti) {
+            my %DisableFilters;
+            foreach my $filter (grep {$_->SUPPORTED_CONTEXT & Form::Filter::CTX_SET} map {$_->Instance} $schemaChild->Filters) {
+                
+                my $result = $filter->Invoke($this->{$Children}{$schemaChild->Name},Form::Filter::CTX_SET,$schemaChild,$this);
+                if ($result->State == Form::FilterResult::STATE_ERROR) {
+                    push @errors,$result;
+                    # íå ïðîâåðÿòü äðóãèå ôèëüòðû âîîáùå
+                    next CHILD_LOOP;
+                } elsif ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
+                    # íå ïðîâåðÿòü äðóãèå ôèëüòðû âîîáùå
+                    next CHILD_LOOP;
+                } elsif ($result->State == Form::FilterResult::STATE_SUCCESS_STAY) {
+                    # íå ïðîâåðÿòü äàííûé ôèëüòð íà êàæäîì ýêçåìïëÿðå
+                    $DisableFilters{$filter} = 1;
+                } else {
+                    # STATE_SUCCESS - âñå îê
+                }
+            }
+            
+            $_ and push @errors,$_->Validate(\%DisableFilters) foreach grep !$_->isEmpty, $this->GetChild($schemaChild->Name);
+            
+        } else {
+            my %DisableFilters;
+            
+            # ïðîâåðÿåì ôèëüòðû, êîòîðûå ìîãóò ïðèìåíÿòüñÿ íà íåñóùåñòâóþùåì çíà÷åíèè
+            foreach my $filter (grep { $_->SUPPORTED_CONTEXT & Form::Filter::CTX_SINGLE and not $_->SUPPORTED_CONTEXT & Form::Filter::CTX_EXISTENT} map {$_->Instance} $schemaChild->Filters) {
+                my $result = $filter->Invoke($this->{$Children}{$schemaChild->Name},Form::Filter::CTX_SINGLE,$schemaChild,$this);
+                
+                if ($result->State == Form::FilterResult::STATE_ERROR) {
+                    push @errors,$result;
+                    # íå ïðîâåðÿòü äðóãèå ôèëüòðû âîîáùå
+                    next CHILD_LOOP;
+                } elsif ($result->State == Form::FilterResult::STATE_SUCCESS_STOP) {
+                    # íå ïðîâåðÿòü äðóãèå ôèëüòðû âîîáùå
+                    next CHILD_LOOP;
+                } else {
+                    # STATE_SUCCESS(_STAY) - âñå îê
+                    $DisableFilters{$filter} = 1;
+                }
+            }
+            
+            # åñëè çíà÷åíèå ñóùåñòâóåò, òî ïðèìåíÿåì îñòàâøèåñÿ ôèëüòðû
+            push @errors,$this->{$Children}{$schemaChild->Name}->Validate(\%DisableFilters) if $this->{$Children}{$schemaChild->Name};
+        }
+        
+    }
+    
+    return @errors;
+}
+
+sub Dispose {
+    my ($this) = @_;
+    
+    foreach my $child (values %{ $this->{$Children} || {} }) {
+        if (ref $child eq 'ARRAY') {
+            foreach my $inst (@$child) {
+                $inst->Dispose;
+            }
+        } else {
+            die new IMPL::Exception("Child is null",%{ $this->{$Children} }) if not $child;
+            $child->Dispose;
+        }
+    }
+    
+    delete @$this{$Schema,$Children};
+    
+    $this->SUPER::Dispose;
+}
+1;
\ No newline at end of file