49
+ − 1 package IMPL::ORM::Schema;
+ − 2 use strict;
+ − 3 use warnings;
+ − 4
+ − 5 use base qw(IMPL::DOM::Document);
+ − 6 use IMPL::Class::Property;
+ − 7 require IMPL::ORM::Schema::Entity;
+ − 8 require IMPL::ORM::Schema::ValueType;
+ − 9
+ − 10 our %CTOR = (
+ − 11 'IMPL::DOM::Document' => sub { nodeName => 'ORMSchema' }
+ − 12 );
+ − 13
+ − 14 BEGIN {
+ − 15 public property mapValueTypes => prop_get | owner_set;
+ − 16 public property mapReferenceTypes => prop_get | owner_set;
+ − 17 public property mapPending => prop_get | owner_set;
+ − 18 public property prefix => prop_get | owner_set;
+ − 19 }
+ − 20
+ − 21 sub CTOR {
+ − 22 my ($this ) = @_;
+ − 23 $this->mapValueTypes({});
+ − 24 $this->mapReferenceTypes({});
+ − 25 $this->mapPending({});
+ − 26 }
+ − 27
+ − 28 # return an entity for the specified typename
+ − 29 # makes forward declaration if nesessary
+ − 30 sub resolveType {
+ − 31 my ($this,$typeName) = @_;
+ − 32
+ − 33 $this = ref $this ? $this : $this->instance;
+ − 34
+ − 35 if (my $entity = $this->mapReferenceTypes->{$typeName}) {
+ − 36 return $entity;
+ − 37 } elsif (UNIVERSAL::isa($typeName,'IMPL::ORM::Object')) {
+ − 38 return $this->declareReferenceType($typeName);
+ − 39 } else {
+ − 40 return undef;
+ − 41 }
+ − 42 }
+ − 43
+ − 44 sub declareReferenceType {
+ − 45 my ($this,$typeName) = @_;
+ − 46
+ − 47 my $entity = new IMPL::ORM::Schema::Entity($typeName->entityName);
+ − 48
+ − 49 $this->mapPending->{$typeName} = $entity;
+ − 50
+ − 51 $this->appendChild($entity);
+ − 52
+ − 53 return $this->mapReferenceTypes->{$typeName} = $entity;
+ − 54 }
+ − 55
+ − 56 sub _addReferenceType {
+ − 57 my ($this,$className) = @_;
+ − 58
+ − 59 if ( my $entity = delete $this->mapPending->{$className} ) {
+ − 60 $className->ormGetSchema($this,$entity);
+ − 61 } else {
+ − 62 return $this->appendChild( $this->mapReferenceTypes->{$className} = $className->ormGetSchema($this) );
+ − 63 }
+ − 64
+ − 65 }
+ − 66
+ − 67 # returns valuetype name
+ − 68 sub isValueType {
+ − 69 my ($this,$typeName) = @_;
+ − 70
+ − 71 $this = ref $this ? $this : $this->instance;
+ − 72
+ − 73 return $this->mapValueTypes->{$typeName};
+ − 74 }
+ − 75
+ − 76 my %instances;
+ − 77 sub instance {
+ − 78 my ($class) = @_;
+ − 79
+ − 80 return ($instances{$class} || ($instances{$class} = $class->new));
+ − 81 }
+ − 82
+ − 83 sub ValueTypes {
+ − 84 my ($this,%classes) = @_;
+ − 85
+ − 86 $this = ref $this ? $this : $this->instance;
+ − 87
+ − 88 while ( my ($typeName,$typeReflected) = each %classes ) {
+ − 89 $this->mapValueTypes->{$typeName} = $typeReflected;
+ − 90 $this->appendChild(IMPL::ORM::Schema::ValueType->new($typeName,$typeReflected));
+ − 91 }
+ − 92 }
+ − 93
+ − 94 sub Classes {
+ − 95 my ($this,@classNames) = @_;
+ − 96
+ − 97 $this = ref $this ? $this : $this->instance;
+ − 98
+ − 99 $this->_addReferenceType($this->prefix . $_) foreach @classNames;
+ − 100 }
+ − 101
+ − 102 sub usePrefix {
+ − 103 my ($this,$prefix) = @_;
+ − 104
+ − 105 $prefix .= '::' if $prefix and $prefix !~ /::$/;
+ − 106
+ − 107 (ref $this ? $this : $this->instance)->prefix($prefix);
+ − 108 }
+ − 109
+ − 110 sub CompleteSchema {
+ − 111 my ($this) = @_;
+ − 112
+ − 113 $this = ref $this ? $this : $this->instance;
+ − 114
+ − 115 $_->ormGetSchema($this,delete $this->mapPending->{$_}) foreach (keys %{$this->mapPending});
+ − 116 }
+ − 117
+ − 118 1;
+ − 119
+ − 120 __END__
+ − 121
+ − 122 =pod
+ − 123
79
+ − 124 =head1 NAME
+ − 125
+ − 126 C<IMPL::ORM::Schema> ����� ����������� ������� � ����������� ���������.
+ − 127
49
+ − 128 =head1 DESCRIPTION
+ − 129
+ − 130 ����� ������, ������������ ����� DOM ��������, ���������� �������
+ − 131 �������� ��������.
+ − 132
+ − 133 ������ ���� - ��� �������� ��������.
+ − 134
79
+ − 135 =begin code xml
+ − 136
49
+ − 137 <Schema>
+ − 138 <Entity entityName="My_Data_Foo">
+ − 139 <Field fieldName="Doo" fieldType="String"/>
+ − 140 <HasMany name="Boxes" target="My_Data_Box"/>
+ − 141 </Entity>
+ − 142 <Entity entityName="My_Data_Bar">
+ − 143 <Subclass base="My_Data_Foo"/>
+ − 144 <Field fieldName="Timestamp" fieldType="Integer"/>
+ − 145 </Entity>
+ − 146 <Entity entityName="My_Data_Box">
+ − 147 <Field fieldName="Capacity" fieldType="Integer"/>
+ − 148 </Entity>
+ − 149 </Schema>
+ − 150
79
+ − 151 =end code xml
+ − 152
49
+ − 153 =cut