Project

General

Profile

1
<?php
2
require_once('util/utilityFunctions.php');
3
require_once('objects/types.php');
4
require_once('objects/lookups.php');
5

    
6
class Entity {
7
  private $references = array();
8
  private $members = array();
9
  private $referrers = array();
10
  private $tableName;
11
  private $extensionType;
12
  private $inited;
13

    
14
  public function __construct($tableName,$node = null) {
15
    global $eList;
16
    // Entity name = table name
17
    $this->tableName = $tableName;
18
    $this->inited = False;
19
    $this->extensionType = '';
20

    
21
    if(!is_null($node)) {
22
      $this->init($tableName,$node);
23
      $this->inited = True;
24
    }
25
  }
26

    
27
  public function init($tableName,$node) {
28
    global $primitiveTypes;
29
    global $eList;
30
    $xpath = new DOMXPath($node->ownerDocument);
31
    $childNodesXPath = $xpath->query("child::node()",$node);
32
    $childNodes = array();
33
    foreach($childNodesXPath as $childNodeXPath) {
34
      $cNodeName = preg_replace("/.*:/","",$childNode->nodeName);
35
      if(!isIgnoreType($cNodeName)) {
36
        $childNodes[] = $childNodeXPath;
37
      }
38
    }
39

    
40
    for($i = 0; $i < count($childNodes); $i++) {
41
      $childNode = $childNodes[$i];
42

    
43
      $cNodeName = preg_replace("/.*:/","",$childNode->nodeName);
44

    
45
      if(isIgnoreType($cNodeName)) {
46
        continue;
47
      }
48

    
49
      #Very inefficient, but I want to be sure that I've handled all possible
50
      #attribute types.
51
      $attrs = $xpath->query("attribute::*",$childNode);
52
      foreach($attrs as $attr) {
53
        $attrName = $attr->name;
54
        if(!isKnownAttribute($attrName)) {
55
          throw new Exception("Encountered unkown attribute: $attrName in element $this->tableName.");
56
        }
57
      }
58

    
59
      switch($cNodeName) {
60
        case 'any':
61
          $any_e = $eList->newEntity($tableName . "_any_nodes");
62
          $any_e->addMember("node_name","models.CharField(max_length=255)");
63
          $any_e->addMember("node_value","models.TextField()");
64
          $any_e->addOneToManyReference($tableName . "_id",$this);
65
          $this->referrers['anyNode'] = $tableName . '_any_nodes';
66
          break;
67
        case 'anyAttribute':
68
          $any_a = $eList->newEntity($tableName . "_any_attr");
69
          $any_a->addMember("attr_name","models.CharField(max_length=255)");
70
          $any_a->addMember("attr_value","models.CharField(max_length=255)");
71
          $any_a->addOneToManyReference($tableName . "_id",$this);
72
          $this->referrers['anyAttribute'] = $tableName . '_any_attr';
73
          break;
74
        case 'attribute':
75
          $a_name = $childNode->getAttribute('name');
76
          if($a_name == '') {
77
            throw new Exception("Nodes defining attributes must have a name.  " .
78
                                "Unnamed attribute node found in $this->tableName.");
79
          }
80
          $default = $childNode->getAttribute('default');
81
          $use = $childNode->getAttribute('use');
82
          $type = preg_replace("/.*:/","",$childNode->getAttribute('type'));
83
          $guess = False;
84
          if($primitiveTypes[$type] != '') {
85
            $def = $primitiveTypes[$type];
86
          } else {
87
            $def = "models.CharField(max_length=255";
88
          }
89
          if($use == 'optional') {
90
            if($def == 'models.CharField(max_length=255') { $def .= ", "; }
91
            $def .= "null=True, blank=True";
92
          }
93
          if($default != '') {
94
            if($use == 'optional' ||
95
               $def == 'models.CharField(max_length=255') {
96
              $def .= ", "; 
97
            }
98
            $def .= "default = '$default'";
99
          }
100
          if(needsIndex("attr_$a_name")) {
101
            if($use == 'optional' ||
102
               $def == 'models.CharField(max_length=255' ||
103
               $default != '') {
104
              $def .= ", "; 
105
            }
106
            $def .= "db_index=True";
107
          }
108
          $def .= ")";
109
          if($guess) { $def .= " # This is a guess"; }
110
          $this->addMember("attr_$a_name",$def);
111
          break;
112
        #Untested
113
        case 'group':
114
          if(hasImportantNodes($childNode)) {
115
            throw new Exception("No defined functionality for group nodes defining complex entities " .
116
                                "within other complex entities.");
117
          }
118
          $ref = preg_replace("/.*:/","",$childNode->getAttribute('ref'));
119
          if($ref == '') {
120
            throw new Exception("No defined functionality for group nodes " .
121
                                "that don't have a 'ref' attribute.");
122
          }
123
          $this->determineRelationship($ref,$ref,$childNode);
124
          break;
125
        case 'complexType':
126
          $name = $childNode->getAttribute('name');
127
          if($name != '') {
128
            throw new Exception("Named complexType definition within entity definition. " .
129
                                "This functionality is not yet implemented.");
130
          }
131
        case 'simpleType':
132
          $name = $childNode->getAttribute('name');
133
          if(isPrimitiveType($name)) {
134
            break;
135
          }
136
          if($name != '') {
137
            throw new Exception("Named simpleType definition within entity definition. " .
138
                                "This functionality is not yet implemented.");
139
          }
140
        case 'choice':
141
          # Fracking hack
142
          $isChoice = True;
143
        case 'complexContent':
144
        case 'simpleContent':
145
        case 'sequence':
146
          $minOccurs = $childNode->getAttribute('minOccurs');
147
          if($isChoice) {
148
            $minOccurs = 0;
149
          }
150
          $maxOccurs = $childNode->getAttribute('maxOccurs');
151
         
152
          #If defined, need to use pass these attribues through to child nodes.
153
          #Then, we add the grandchid nodes to the node list since we need the
154
          #grandchild nodes to complete the entity definition.
155
          $grandchildNodesXPath = $xpath->query("child::node()",$childNode);
156
          foreach($grandchildNodesXPath as $grandchildNodeXPath) {
157
            $gcNodeName = preg_replace("/.*:/","",$grandchildNodeXPath->nodeName);
158
            if(isIgnoreType($gcNodeName)) {
159
              continue;
160
            }
161

    
162
            if(((string)$minOccurs) != '') {
163
              $grandchildNodeXPath->setAttribute("minOccurs",$minOccurs);
164
            }
165
            if(((string)$maxOccurs) != '') {
166
              $grandchildNodeXPath->setAttribute("maxOccurs",$maxOccurs);
167
            }
168
            $childNodes[] = $grandchildNodeXPath;
169
          }
170

    
171
          #None of these have implemented functionality, need to fail if we reach
172
          #them during exection.
173
          $err_type = '';
174
          $default = $childNode->getAttribute('default');
175
          if($default != '' ) {
176
            $err_type = "default";
177
          }
178
          $use = $childNode->getAttribute('use');
179
          if($use != '' ) {
180
            $err_type = "use";
181
          }
182
          $mixed = $childNode->getAttribute('mixed');
183
          if($mixed != '' ) {
184
            $err_type = "mixed";
185
          }
186
          $type = $childNode->getAttribute('type');
187
          if($type != '' ) {
188
            $err_type = "type";
189
          }
190
          $namespace = $childNode->getAttribute('namespace');
191
          if($namespace != '' ) {
192
            $err_type = "namespace";
193
          }
194
          $nillable = $childNode->getAttribute('nillable');
195
          if($nillable != '' ) {
196
            $err_type = "nillable";
197
          }
198
          $ref = $childNode->getAttribute('ref');
199
          if($ref != '' ) {
200
            $err_type = "ref";
201
          }
202
          $base = $childNode->getAttribute('base');
203
          if($base != '' ) {
204
            $err_type = "base";
205
          }
206
          if($err_type != '') {
207
            throw new Exception("$err_type not defined for pass-through.");
208
          }
209
          break;
210
        case 'element':
211
          $this->handleElementCase($childNode);
212
          break;
213
        case 'extension':
214
          $name = findFirstAncestorName($childNode);
215
          $base = preg_replace("/.*:/","",$childNode->getAttribute('base'));
216
          if(isPrimitiveType($base)) {
217
            $grandchildNodesXPath = $xpath->query("child::node()",$childNode);
218
            foreach($grandchildNodesXPath as $grandchildNodeXPath) {
219
              $gcNodeName = preg_replace("/.*:/","",$grandchildNodeXPath->nodeName);
220
              if(isIgnoreType($gcNodeName)) {
221
                continue;
222
              }
223
              if($gcNodeName != 'attribute') {
224
                throw new Exception("Extension of primitive types can only add attributes, ".
225
                                    "found $gcNodeName.");
226
              }
227
              $a_name = $grandchildNodeXPath->getAttribute('name');
228
              if($a_name == '') {
229
                throw new Exception("Nodes defining attributes must have a name.  " .
230
                                    "Unnamed attribute node found in $this->tableName.");
231
              }
232
              $default = $grandchildNodeXPath->getAttribute('default');
233
              $use = $grandchildNodeXPath->getAttribute('use');
234
              $type = preg_replace("/.*:/","",$grandchildNodeXPath->getAttribute('type'));
235
              $guess = False;
236
              if($primitiveTypes[$type] != '') {
237
                $def = $primitiveTypes[$type];
238
              } else {
239
                $def = "models.CharField(max_length=255";
240
                $guess = True;
241
              }
242
              if($use == 'optional') {     
243
                if($def == 'models.CharField(max_length=255') { $def .= ", "; }
244
                $def .= "null=True, blank=True";
245
              }
246
              if($default != '') {
247
                if($use == 'optional' ||
248
                   $def == 'models.CharField(max_length=255') { $def .= ", "; }
249
                $def .= "default = '$default'";
250
              }
251
              if(needsIndex("attr_$a_name")) {
252
                if($use == 'optional' ||
253
                   $def == 'models.CharField(max_length=255' ||
254
                   $default != '') {
255
                  $def .= ", "; 
256
                }
257
                $def .= "db_index=True";
258
              }
259
              $def .= ")";
260
              if($guess) { $def .= " # This is a guess"; }
261
              $this->addMember("attr_$a_name",$def);
262
            }
263
            $def = $primitiveTypes[$base] . ")";
264
            $this->addMember("primitive_type_value",$def);
265
          } else {
266
            $ref_e = $eList->getEntityForReference($base);
267
//            $this->addOneToOneReference($base . "_extend",$ref_e);
268
             $this->addOneToManyReference($base . "_extend",$ref_e,False);
269
            $this->extensionType = $base;
270

    
271
            $grandchildNodesXPath = $xpath->query("child::node()",$childNode);
272
            foreach($grandchildNodesXPath as $grandchildNodeXPath) {
273
              $gcNodeName = preg_replace("/.*:/","",$grandchildNodeXPath->nodeName);
274
              if(isIgnoreType($gcNodeName)) {
275
                continue;
276
              }
277
              $childNodes[] = $grandchildNodeXPath;
278
            }
279
          }
280
          break;
281
        case 'restriction':
282
        case 'union':
283
        case 'maxInclusive':
284
        case 'minInclusive':
285
        case 'minExclusive':
286
        case 'list':
287
        case 'pattern':
288
        case 'fractionDigits':
289
          throw new Exception("No functionality defined for nodes of type: $cNodeName");
290
          break;
291
        default:
292
          throw new Exception("Encountered uknown nodes type: $cNodeName");
293
          break;
294
      }
295
    }
296
  }
297

    
298
  public function handleElementCase($childNode) {
299
    global $eList;
300
    global $primitiveTypes;
301
    $ref = preg_replace("/.*:/","",$childNode->getAttribute('ref'));
302
    $type = preg_replace("/.*:/","",$childNode->getAttribute('type'));
303
    if($ref != '') { 
304
      $type = $ref; 
305
    }
306
    $name = $childNode->getAttribute('name');
307
    if($ref != '' && $name == '' /*&& !isPrimitiveType($ref)*/) {
308
      $name = $ref;
309
    }
310

    
311
    if($name == '') {
312
      throw new Exception("All element nodes must have a name attribute, " .
313
                          "or a ref attribute to serve as the name.");
314
    }
315

    
316
    if($type != '') {
317
      $this->determineRelationship($name,$type,$childNode);
318
    } else {
319
      #Very hacky, but there a some cases where the element
320
      #has no type, and either 1) has some children nodes, but none of the
321
      #children nodes define a type, or 2) Has no useful nodes at all.
322
      # In this case the node is considered to be an anyType.
323
      $isDefined = False;
324
      $xpath = new DOMXPath($childNode->ownerDocument);
325
      $grandchildNodesXPath = $xpath->query("child::node()",$childNode);
326
      foreach($grandchildNodesXPath as $grandchildNodeXPath) {
327
        $gcNodeName = preg_replace("/.*:/","",$grandchildNodeXPath->nodeName);
328
        if(isIgnoreType($gcNodeName)) {
329
          continue;
330
        }
331
        if(hasImportantNodes($grandchildNodeXPath) || $grandchildNodeXPath->hasAttributes()) {
332
          $isDefined = True;
333
        }
334
      }
335
      if(!$isDefined) {
336
        $primitiveTypes[$name] = 'models.TextField(';
337
      }
338
      
339
      if(!isPrimitiveType($name)) {
340
        $eList->newEntity($name,$childNode);
341
      }
342
      $this->determineRelationship($name,$name,$childNode);
343
    }
344
  }
345

    
346
  public function determineRelationship($colName,$typeName,$node) {
347
    global $eList;
348
    global $primitiveTypes;
349
    global $nativeVegXPointers;
350
    global $manyToManyRelationships;
351

    
352
    $tableName = $this->tableName;
353

    
354
    $minOccurs = $node->getAttribute('minOccurs');
355
    $optional = $minOccurs == 0 ? True : False;
356
    $maxOccurs = $node->getAttribute('maxOccurs');
357
    $default = $node->getAttribute('default');
358
    $default = $node->getAttribute('use');
359

    
360
    if(isNativePointer($colName)) {
361
      $def = $nativeVegXPointers[$colName]['def'];
362
      $this->addMember($colName,$def);
363
    } else if(isPrimitiveType($typeName)) {
364
      $def = $primitiveTypes[$typeName];
365
      if($use == 'optional' || $optional) {
366
        if($def == 'models.CharField(max_length=255') { $def .= ", "; }
367
        $def .= "null=True, blank=True";
368
      }
369
      if($default != '') {
370
        if($use == 'optional' || $optional || 
371
           $def == 'models.CharField(max_length=255') { 
372
          $def .= ", "; 
373
        }
374
        $def .= "default = '$default'";
375
      }
376
      if(needsIndex("$colName")) {
377
        if($use == 'optional' || $optional ||
378
           $def == 'models.CharField(max_length=255' ||
379
           $default != '') {
380
          $def .= ", "; 
381
        }
382
        $def .= "db_index=True";
383
      }
384
      $def .= ")";
385

    
386
      if(((string)$maxOccurs) == '' || $maxOccurs == 1) {
387
        $this->addMember($colName,$def);
388
      } else {
389
        $refName = $this->tableName . "_" . $colName;
390
        $new_e = $eList->getEntityForReference($refName);
391
        $new_e->addMember("primitive_type_value",$def);
392
        $new_e->addOneToManyReference($tableName . "_id",$this);
393
        $this->referrers[$colName] = $refName;
394
      }
395
    } else {
396
      $ref_e = $eList->getEntityForReference($typeName);
397
      if(((string)$maxOccurs) == '' || $maxOccurs == 1) {
398
        //$this->addOneToOneReference($colName,$ref_e,$optional);
399
        $this->addOneToManyReference($colName,$ref_e,False,$optional);
400
      } else {
401
#        echo "Need to define relationship between:\n  $tableName <--> $typeName\n";
402
#        echo "    (O)ne to Many\n    (M)any to Many\n";
403
#        echo "    Your choice:  ";
404
#        $handle = fopen ("php://stdin","r");
405
#        $line = fgets($handle);
406
        $line = 'O';
407
        if($manyToManyRelationships[$tableName][$typeName]) {
408
          $line = 'M';
409
        }
410
        if(trim($line) == 'O' || trim($line) == 'o'){
411
          $ref_e->addOneToManyReference($tableName . "_id",$this,False,$optional);
412
          $this->referrers[$colName] = $ref_e->getName();
413
        } else {
414
          $this->addManyToManyReference($colName,$ref_e,$tableName . "_" . $typeName . "_" . $colName);
415
        }
416
      }
417
    }
418
  }
419

    
420
  private function addReference($colName,$definition) {
421
    # Probably shouldn't allow duplicate entries, most likely points to a problem.
422
    if(array_key_exists($colName,$this->references)) {
423
     $curDef = $this->references[$colName];
424
     throw new Exception("Attempting to overwrite/reinsert member $colName:$curDef with $colName:$definition in entity " . $this->tableName . ".");
425
    }
426
    $this->references[$colName] = $definition;
427
  }
428

    
429
  public function isInited() {
430
    return $this->inited;
431
  }
432

    
433
  public function addOneToOneReference($colName,$e,$optional = False) {
434
    $eName = $e->getName();
435
    $relatedName = $this->tableName . "_" . $colName;
436
    $def = "models.ForeignKey('$eName', unique=True,related_name='$relatedName'";
437
    if($optional) {
438
      $def .= ", null=True, blank=True";
439
    }
440
    $def .= ")";
441
    $this->addReference($colName,$def); 
442
  }
443

    
444
  public function addOneToManyReference($colName,$e,$primitiveRef = True,$optional = False) {
445
    $eName = $e->getName();
446
    if($eName == $this->tableName) { 
447
      $eName = 'self'; 
448
    }
449
    $relatedName = $this->tableName . "_" . $colName;
450
    #$def = "models.OneToOneField('$eName', primary_key=True,related_name='$relatedName'";
451
    $def = "models.ForeignKey('$eName', related_name='$relatedName'";
452
    if($optional) {
453
      $def .= ", null=True, blank=True";
454
    }
455
    $def .= ")";
456
    if(!$primitiveRef) {
457
      $def .= " #Complex one2Many";
458
    }
459
    $this->addReference($colName,$def); 
460
  }
461

    
462
  public function addManyToManyReference($colName,$e,$db_table = '') {
463
    $eName = $e->getName();
464
    $relatedName = $this->tableName . "_" . $colName;
465

    
466
    $def = "models.ManyToManyField('$eName',related_name='$relatedName'";
467

    
468
    #Django chokes if the table/relation names are too long.  54 characters seems to
469
    #be a decent magic number.
470
    if($db_table != '' && strlen($db_table) > 54) {
471
      $db_table = 'v_' . substr($db_table,0,54);
472
      $def .= ",db_table = '$db_table'";
473
    }
474
    $def .= ")";
475
    $this->addReference($colName,$def); 
476
  }
477

    
478
  public function addMember($colName, $definition) {
479
    # Probably shouldn't allow duplicate entries, most likely points to a problem.
480
    if(array_key_exists($colName,$this->members)) {
481
      $curDef = $this->members[$colName];
482
      if($curDef != $definition) {
483
        throw new Exception("Attempting to overwrite/reinsert member $colName:$curDef with $colName:$definition.");
484
      }
485
    }
486
    $this->members[$colName] = $definition;
487
  }
488

    
489
  public function getName() {
490
    return $this->tableName;
491
  }
492

    
493
  public function getReferences() {
494
    return $this->references;
495
  }
496

    
497
  public function getMembers() {
498
    return $this->members;
499
  }
500

    
501
  public function getReferrers() {
502
    return $this->referrers;
503
  }
504

    
505
  public function postProcess() {
506
    global $eList;
507

    
508
    #If we're dealing with extensions we need to pull the members, references, &
509
    #referrers of the base class.
510
    if($this->extensionType != '') {
511
      $base = $eList->getEntityForReference($this->extensionType);
512
      $baseReferences = $base->getReferences();
513
      $baseMembers = $base->getMembers();
514
      $baseReferrers = $base->getReferrers();
515

    
516
      $this->references = array_merge($this->references,$baseReferences);
517
      foreach(array_keys($this->references) as $k) {
518
        $def = $this->references[$k];
519
        $baseToken = $base->getName() . "_";
520
        $tableToken = $this->tableName . "_";
521
        $def = preg_replace("/$baseToken/","$tableToken",$def);
522
        $this->references[$k] = $def;
523
      }
524
        
525
      $this->members = array_merge($this->members,$baseMembers);
526
      $this->referrers = array_merge($this->referrers,$baseReferrers);
527

    
528
    }
529

    
530
  }
531

    
532
  public function toString() {
533
    global $tableRenames;
534
    $str = "class " . $this->tableName . "(models.Model):\n";
535

    
536
    #All entities need reference to their creation info since
537
    #VegX does not support unique identification for all types of information,
538
    #at least not as defined in BIEN3.
539
    $str .= "  entryInfo = models.ForeignKey('EntryInfo')\n";
540

    
541
    foreach(array_keys($this->references) as $colName) {
542
      $def = $this->references[$colName];
543
      $effectiveColName = $tableRenames[$colName] == null ? $colName : $tableRenames[$colName];
544
      $str .= "  $effectiveColName = $def\n";
545
    }
546
    foreach(array_keys($this->members) as $colName) {
547
      $def = $this->members[$colName];
548
      $str .= "  $colName = $def\n";
549
    }
550

    
551
    global $geoSpatialTypes;
552
    if($geoSpatialTypes[$this->tableName]) {
553
      //Only one geometry type per table currently so this works.
554
      $geoColDef = $geoSpatialTypes[$this->tableName]['colDef']; 
555
      $str .= "  \n  # GeoDjango-specific: a geometry field, and\n".
556
              "  # overriding the default manager with a GeoManager instance.\n".
557
              "  $geoColDef\n".
558
              "  objects = models.GeoManager()\n";
559

    
560
    }
561

    
562
    $str .= "\n" . $this->makeExportFunction();
563
    $str .= "\n" . $this->makeImportFunction();
564
    $str .= "\n" . $this->makeExportDummyDataFunction();
565
    $str .= "\n" . $this->makeRetrieveOrNewFunction();
566

    
567
    #truncate table names that are too long for Django/Postgre to support
568
    if(strlen($this->tableName) > 54) {
569
      $tabName = 'v_' . substr($this->tableName,0,54);
570
      $str .= "\n\n  class Meta:\n".
571
              "    db_table = u'$tabName'\n\n";
572
    }
573

    
574
    #there is a tablename resolution conflict between taxonNames/TaxonNames, taxonConcepts/TaxonConcepts,
575
    #temporalCoverage/TemporalCoverage in
576
    #that Django & Postgres store the table names in a case-insensitive way.  Need to force the table name
577
    #to be something different here.
578
    if($this->tableName == 'taxonNames') {
579
      $str .= "\n\n  class Meta:\n".
580
              "    db_table = u'v_taxonnames_lc'\n\n";
581
    } else if($this->tableName == 'TaxonNames') {
582
      $str .= "\n\n  class Meta:\n".
583
              "    db_table = u'v_taxonnames_uc'\n\n";
584
    } else if($this->tableName == 'taxonConcepts') {
585
      $str .= "\n\n  class Meta:\n".
586
              "    db_table = u'v_taxonconcepts_lc'\n\n";
587
    } else if($this->tableName == 'TaxonConcepts') {
588
      $str .= "\n\n  class Meta:\n".
589
              "    db_table = u'v_taxonconcepts_uc'\n\n";
590
    } else if($this->tableName == 'temporalCoverage') {
591
      $str .= "\n\n  class Meta:\n".
592
              "    db_table = u'v_temporalcoverage_lc'\n\n";
593
    } else if($this->tableName == 'TemporalCoverage') {
594
      $str .= "\n\n  class Meta:\n".
595
              "    db_table = u'v_temporalcoverage_uc'\n\n";
596
    }
597

    
598
    return $str;
599
  }
600

    
601
  public function makeImportFunction() {
602
    global $tableRenames;
603
    #Slightly different if there are no members
604
    if(count($this->references) == 0 &&
605
       count($this->members) == 0 &&
606
       count($this->referrers) == 0) {
607
      return "  def importVegX(self,node,info):\n".
608
             "    self.entryInfo = info\n".
609
             "    self.save()\n";
610
    }
611

    
612
    $def =  "  def importVegX(self,node,info):\n".
613
            "    self.entryInfo = info\n";
614

    
615
    if(preg_match_all("/([a-zA-Z]*)_extend/",implode(",",array_keys($this->references)),$matches) > 0) {
616
      $base = $matches[1][0];
617
      $def .= "    extendedEl = $base().retrieveOrNew(node)\n".
618
              "    extendedEl.importVegX(node,info)\n".
619
              "    self.$base"."_extend = extendedEl\n\n";
620
    }
621

    
622
    $def .= "    self.save()\n";
623

    
624
    #Fun hack for anyAttribute & anyNode nodes
625
    if(preg_match("/_any_attr/",$this->tableName,$matches) > 0 ||
626
       preg_match("/_any_nodes/",$this->tableName,$matches) > 0) {
627
      return $def;
628
    }
629

    
630
    if(preg_match("/attr_/",implode(",",array_keys($this->members))) > 0 ||
631
       preg_match("/anyAttribute/",implode(",",array_keys($this->referrers))) > 0) {
632
      $def .= "    #attributes\n".
633
              "    for attr in node.attributes.keys():\n".
634
              "      aName = 'attr_' + attr\n".
635
              "      aVal = node.attributes[attr].nodeValue\n";
636
      $i = 0;
637
      foreach(array_keys($this->members) as $colName) {
638
        $ifStmt = $i == 0 ? 'if' : 'elif';
639
        if(preg_match("/^attr_/",$colName,$matches) > 0) {
640
          $i += 1;
641
          if(preg_match("/BooleanField/",$this->members[$colName],$matches) > 0) {
642
            $def .= "      $ifStmt aName == '$colName' and (aVal == 'true' or\n".
643
                    "      aVal == 'false' or aVal == 0 or aVal == 1):\n".
644
                    "        self.$colName = (aVal == 'true' or aVal == 1)\n";
645
          } else {
646
            $def .= "      $ifStmt aName == '$colName':\n".
647
                    "        self.$colName = aVal\n";
648
          }
649
        }
650
      }
651
    }
652
    if(preg_match("/anyAttribute/",implode(",",array_keys($this->referrers))) > 0) {
653
      $type = $this->referrers['anyAttribute'];
654
      $tIDName = $this->tableName . "_id";
655
      if(preg_match_all("/attr_/",implode(",",array_keys($this->members)),$matches) > 0) {
656
        $def .= "      else:\n".
657
                "        newEl = $type()\n".
658
                "        newEl.$tIDName = self\n".
659
                "        newEl.attr_name = attr\n".
660
                "        newEl.attr_value = aVal\n".
661
                "        newEl.entryInfo = info\n".
662
                "        newEl.save()\n";
663
      } else {
664
        $def .= "      newEl = $type()\n".
665
                "      newEl.$tIDName = self\n".
666
                "      newEl.attr_name = attr\n".
667
                "      newEl.attr_value = aVal\n".
668
                "      newEl.entryInfo = info\n".
669
                "      newEl.save()\n";
670
      }
671
    }
672
  
673
    if(count($this->members) - 
674
       preg_match_all("/attr_/",implode(",",array_keys($this->members)),$matches) -
675
       preg_match_all("/primitive_type_value/",implode(",",array_keys($this->members)),$matches) > 0 ||
676
       count($this->references) > 0 || count($this->referrers) > 0) {
677
      $def .= "    #members & relationships\n".
678
              "    for child in node.childNodes:\n".
679
              "      cName = child.nodeName\n";
680
    }
681

    
682
    $i = 0;
683
    if(count($this->members) - 
684
       preg_match_all("/attr_/",implode(",",array_keys($this->members)),$matches) -
685
       preg_match_all("/primitive_type_value/",implode(",",array_keys($this->members)),$matches) > 0) {
686
      foreach(array_keys($this->members) as $colName) {
687
        if(preg_match("/^attr_/",$colName) > 0) { continue; }
688
        else if(isNativePointer($colName)) {
689
          global $nativeVegXPointers;
690
          $ifStmt = $i == 0 ? 'if' : 'elif';
691
          $i += 1;
692
          $tabType = $nativeVegXPointers[$colName]['fk_type'];
693
          $toField = $nativeVegXPointers[$colName]['to_field'];
694
          $effectiveColName = $tableRenames[$colName] == null ? $colName : $tableRenames[$colName];
695
          $def .= "      $ifStmt cName == '$effectiveColName':\n".
696
                  "        if(len(child.childNodes) > 0):\n".
697
                  "          cVal = child.childNodes[0].nodeValue\n".
698
                  "          q = $tabType.objects.filter($toField" . "__exact = cVal)\n".
699
                  "          q = $tabType.objects.filter(entryInfo__id__exact = self.entryInfo.id)\n".
700
                  "          if len(q) > 0:\n".
701
                  "            self.$effectiveColName = q[0]\n";
702
        } else {
703
          $ifStmt = $i == 0 ? 'if' : 'elif';
704
          $i += 1;
705
          $effectiveColName = $tableRenames[$colName] == null ? $colName : $tableRenames[$colName];
706
          $def .= "      $ifStmt cName == '$effectiveColName':\n".
707
                  "        if(len(child.childNodes) > 0):\n".
708
                  "          cVal = child.childNodes[0].nodeValue\n".
709
                  "          self.$effectiveColName = cVal\n";
710
        }
711
      }
712
    }
713

    
714
    if(preg_match_all("/primitive_type_value/",implode(",",array_keys($this->members)),$matches) > 0) {
715
      $def .= "    if(len(node.childNodes) > 0):\n".
716
              "      cVal = node.childNodes[0].nodeValue\n".
717
              "      self.primitive_type_value = cVal\n";
718
    }
719

    
720
    foreach(array_keys($this->references) as $colName) {
721
      $ifStmt = $i == 0 ? 'if' : 'elif';
722
      $colDef = $this->references[$colName];
723

    
724
      if(preg_match("/(ForeignKey\(')([a-zA-Z]*)/",$colDef,$matches) > 0 &&
725
         preg_match("/Complex one2Many/",$colDef) > 0 && preg_match("/_extend/",$colDef) == 0 &&
726
         preg_match("/_id/",$colName) == 0) {
727
        $i += 1;
728
        $effectiveColName = $tableRenames[$colName] == null ? $colName : $tableRenames[$colName];
729
        $def .= "      $ifStmt cName == '$effectiveColName':\n".
730
                "        newEl = $matches[2]().retrieveOrNew(child)\n".
731
                "        newEl.importVegX(child,info)\n".
732
                "        self.$effectiveColName = newEl\n";
733
      }
734
      if(preg_match("/(ManyToManyField\(')([a-zA-Z]*)/",$colDef,$matches) > 0) {
735
        $effectiveColName = $tableRenames[$colName] == null ? $colName : $tableRenames[$colName];
736
        $i += 1;
737
        $def .= "      $ifStmt cName == '$effectiveColName':\n".
738
                "        newEl = $matches[2]().retrieveOrNew(child)\n".
739
                "        newEl.importVegX(child,info)\n".
740
                "        self.$effectiveColName.add(newEl)\n";
741
      }
742
    }
743

    
744
    if(count($this->referrers) > 0) {
745
      $def .= "      #These are the elements that refer to this one\n";
746
    }
747
    $allowAnyNode = False;
748
    foreach(array_keys($this->referrers) as $colName) {
749
      if($colName == 'anyAttribute' || $colName == 'anyNode') { continue; }
750
      $ifStmt = $i == 0 ? 'if' : 'elif';
751
      $i += 1;
752
      $colDef = $this->referrers[$colName];
753
      $elReferenceBack = $this->tableName . '_id';
754
      $effectiveColName = $tableRenames[$colName] == null ? $colName : $tableRenames[$colName];
755
      $def .= "      $ifStmt cName == '$effectiveColName':\n".
756
              "        newEl = $colDef().retrieveOrNew(child)\n".
757
              "        newEl.$elReferenceBack = self\n".
758
              "        newEl.importVegX(child,info)\n";
759
    }
760
    if(preg_match("/anyNode/",implode(",",array_keys($this->referrers))) > 0) {
761
      $type = $this->referrers['anyNode'];
762
      $tIDName = $this->tableName . "_id";
763
      if($i > 0) {
764
        $def .= "      else:\n".
765
                "        newEl = $type()\n".
766
                "        newEl.$tIDName = self\n".
767
                "        newEl.node_name = cName\n".
768
                "        for grandchild in child.childNodes:\n".
769
                "          newEl.node_value += grandchild.toxml()\n".
770
                "        newEl.entryInfo = info\n".
771
                "        newEl.save()\n";
772
      } else {
773
        $def .= "      newEl = $type()\n".
774
                "      newEl.$tIDName = self\n".
775
                "      newEl.node_name = cName\n".
776
                "      for grandchild in child.childNodes:\n".
777
                "        newEl.node_value += grandchild.toxml()\n".
778
                "      newEl.entryInfo = info\n".
779
                "      newEl.save()\n";
780
      }
781
    }
782

    
783
    global $geoSpatialTypes;
784
    if($geoSpatialTypes[$this->tableName]) {
785
      //Only one geometry type per table currently so this works.
786
      $geoColImportDef = $geoSpatialTypes[$this->tableName]['importDef']; 
787
      $def .= "  \n    # Convert to geometry types to make use of GeoDjango's\n".
788
              "    # capabilities.\n".
789
              "  $geoColImportDef\n";
790

    
791
    }
792

    
793
    $def .= "\n    self.save()\n"; 
794
    return $def;
795
    
796
  }
797

    
798
  public function makeExportFunction() {
799
    global $tableRenames;
800

    
801
    #Slightly different if there are no members
802
    if(count($this->references) == 0 &&
803
       count($this->members) == 0 &&
804
       count($this->referrers) == 0) {
805
      return "  def exportVegX(self,myNode,doc):\n".
806
             "    return myNode\n";
807
    }
808

    
809
    $def =  "  def exportVegX(self,myNode,doc):\n";
810

    
811
    #Fun hack for anyAttribute & anyNode nodes
812
    if(preg_match("/_any_attr/",$this->tableName,$matches) > 0) {
813
      $def .= "    newAttr = doc.createAttribute(self.attr_name)\n".
814
              "    newAttr.value = self.attr_value\n".
815
              "    return newAttr\n";
816
      return $def;
817
    }
818
    if(preg_match("/_any_nodes/",$this->tableName,$matches) > 0) {
819
      $def .= "    newEl = doc.createElement(self.node_name)\n".
820
              "    newElText = doc.createTextNode(self.node_value)\n".
821
              "    newEl.appendChild(newElText)\n".
822
              "    return newEl\n\n";
823
      return $def;
824
    }
825

    
826
    foreach(array_keys($this->members) as $colName) {
827
      $nodeName = $colName;
828
      $nodeText = "str(self.$colName)";
829
      //Python's string representation of booleans is True/False but xsd requires
830
      //true/false (lowercase) so we need this hack.
831
      if(preg_match("/NullBooleanField/",$this->members[$colName],$matches) > 0) {
832
        $nodeText = "string.lower(str(self.$colName))";
833
      }
834
      if(preg_match("/^attr_/",$colName,$matches) > 0) {
835
        $nodeName = preg_replace("/^attr_/","",$colName);
836
        $def .= "    if self.$colName != None:\n".
837
                "      newAttr = doc.createAttribute('$nodeName')\n".
838
                "      newAttr.value = $nodeText\n".
839
                "      myNode.setAttributeNode(newAttr)\n\n";
840
      } else if(preg_match("/primitive_type_value/",$colName,$matches) > 0) {
841
        $def .= "    if self.$colName != None:\n".
842
                "      newElText = doc.createTextNode(self.$colName)\n".
843
                "      myNode.appendChild(newElText)\n\n";
844
      }else if(isNativePointer($colName)) {
845
        global $nativeVegXPointers;
846
        $to_field = $nativeVegXPointers[$colName]['to_field'];
847
        $nodeText = "str(self.$colName.$to_field)";
848
        $def .= "    if self.$colName != None:\n".
849
                "      newEl = doc.createElement('$colName')\n".
850
                "      newElText = doc.createTextNode($nodeText)\n".
851
                "      newEl.appendChild(newElText)\n".
852
                "      myNode.appendChild(newEl)\n\n";
853
      }else {
854
/*
855
        if(preg_match("/DateField/",$this->members[$colName],$matches) > 0 ||
856
           preg_match("/TimeField/",$this->members[$colName],$matches) > 0 ||
857
           preg_match("/PositiveIntegerField/",$this->members[$colName],$matches) > 0 ||
858
           preg_match("/NullBooleanField/",$this->members[$colName],$matches) > 0 ||
859
           preg_match("/FloatField/",$this->members[$colName],$matches) > 0) {
860
          $nodeText = "str(self.$colName)";
861
        }
862
*/
863
        $def .= "    if self.$colName != None:\n".
864
                "      newEl = doc.createElement('$colName')\n".
865
                "      newElText = doc.createTextNode($nodeText)\n".
866
                "      newEl.appendChild(newElText)\n".
867
                "      myNode.appendChild(newEl)\n\n";
868
      }
869
    }
870

    
871
    foreach(array_keys($this->references) as $colName) {
872
      $colDef = $this->references[$colName];
873

    
874
      if(preg_match("/(ForeignKey\(')([a-zA-Z]*)/",$colDef,$matches) > 0 &&
875
         (preg_match("/Complex one2Many/",$colDef) > 0 || preg_match("/_extend/",$colName) > 0) &&
876
         preg_match("/_id/",$colName) == 0) {
877
        $effectiveColName = $tableRenames[$colName] == null ? $colName : $tableRenames[$colName];
878
        if(preg_match("/_extend/",$colName) == 0) {
879
          $def .= "    if self.$effectiveColName != None:\n".
880
                  "      newEl = doc.createElement('$effectiveColName')\n".
881
                  "      myNode.appendChild(self.$effectiveColName.exportVegX(newEl,doc))\n\n";
882
        } else {
883
          $def .= "    if self.$colName != None:\n".
884
                  "      myNode = self.$colName.exportVegX(myNode,doc)\n\n";
885
        }
886
      }
887
      if(preg_match("/(ManyToManyField\(')([a-zA-Z]*)/",$colDef,$matches) > 0) {
888
        $effectiveColName = $tableRenames[$colName] == null ? $colName : $tableRenames[$colName];
889
        $def .= "    for childRef in self.$colName.all():\n".
890
                "      newEl = doc.createElement('$effectiveColName')\n".
891
                "      myNode.appendChild(childRef.exportVegX(newEl,doc))\n\n";
892
      }
893
    }
894

    
895
    foreach(array_keys($this->referrers) as $nodeName) {
896
      $nodeNameToUse = $this->referrers[$nodeName];
897
      if($nodeName == 'anyAttribute') {
898
        $nodeNameToUse = $this->tableName . '_any_attr';
899
        $relatedName = $nodeNameToUse . '_' . $this->tableName . '_id';
900
        $def .= "    for childRef in self.$relatedName.all():\n".
901
                "      newEl = doc.createAttribute('$nodeName')\n".
902
                "      myNode.setAttributeNode(childRef.exportVegX(newEl,doc))\n\n";
903
      } else {
904
        if($nodeName == 'anyNode') {
905
          $nodeNameToUse = $this->tableName . '_any_nodes';
906
        }
907
        $relatedName = $nodeNameToUse . '_' . $this->tableName . '_id';
908
        $effectiveNodeName = $nodeName;
909
        if($tableRenames[$nodeName] != null) {
910
          $effectiveNodeName = $tableRenames[$nodeName];
911
        }
912
        $def .= "    for childRef in self.$relatedName.all():\n".
913
                "      newEl = doc.createElement('$effectiveNodeName')\n".
914
                "      myNode.appendChild(childRef.exportVegX(newEl,doc))\n\n";
915
      }
916
    }
917

    
918
    $def .= "    return myNode\n";
919
    return $def;
920
  }
921

    
922
  public function makeExportDummyDataFunction() {
923
    global $tableRenames;
924
    #Slightly different if there are no members
925
    if(count($this->references) == 0 &&
926
       count($this->members) == 0 &&
927
       count($this->referrers) == 0) {
928
      return "  def exportDummyVegX(self,myNode,doc,usedObjectsStack):\n".
929
             "    return myNode\n";
930
    }
931

    
932
    $def =  "  def exportDummyVegX(self,myNode,doc,usedObjectsStack):\n";
933

    
934
    #Fun hack for anyAttribute & anyNode nodes
935
    if(preg_match("/_any_attr/",$this->tableName,$matches) > 0) {
936
      $def .= "    newAttr = doc.createAttribute(getRandomString())\n".
937
              "    newAttr.value = getRandomString()\n".
938
              "    return newAttr\n";
939
      return $def;
940
    }
941
    if(preg_match("/_any_nodes/",$this->tableName,$matches) > 0) {
942
      $def .= "    newEl = doc.createElement(getRandomString())\n".
943
              "    newElText = doc.createTextNode(getRandomText())\n".
944
              "    newEl.appendChild(newElText)\n".
945
              "    return newEl\n\n";
946
      return $def;
947
    }
948

    
949
    foreach(array_keys($this->members) as $colName) {
950
      $nodeName = $colName;
951
      $colDef = $this->members[$colName];
952
      $randomFun = "getRandomString";
953
      if(preg_match("/FloatField/",$colDef,$matches) > 0) {
954
        $randomFun = "getRandomFloat";
955
      } else if(preg_match("/IntegerField/",$colDef,$matches) > 0) {
956
        $randomFun = "getRandomInt";
957
      } else if(preg_match("/TextField/",$colDef,$matches) > 0) {
958
        $randomFun = "getRandomText";
959
      } else if(preg_match("/DateField/",$colDef,$matches) > 0) {
960
        $randomFun = "getRandomDate";
961
      } else if(preg_match("/TimeField/",$colDef,$matches) > 0) {
962
        $randomFun = "getRandomTime";
963
      } else if(preg_match("/NullBooleanField/",$colDef,$matches) > 0) {
964
        $randomFun = "getRandomBool";
965
      }
966

    
967
      #Need to explicitly convert to string so minidom doesn't
968
      #roll over in nasty convulsions
969
      $randomFun = "str($randomFun())";
970

    
971
      if(preg_match("/^attr_/",$colName,$matches) > 0) {
972
        $nodeName = preg_replace("/^attr_/","",$colName);
973
        $def .= "    newAttr = doc.createAttribute('$nodeName')\n".
974
                "    newAttr.value = $randomFun\n".
975
                "    myNode.setAttributeNode(newAttr)\n\n";
976
      } else if(preg_match("/primitive_type_value/",$colName,$matches) > 0) {
977
        $def .= "    newElText = doc.createTextNode($randomFun)\n".
978
                "    myNode.appendChild(newElText)\n\n";
979
      }else {
980
        $def .= "    newEl = doc.createElement('$colName')\n".
981
                "    newElText = doc.createTextNode($randomFun)\n".
982
                "    newEl.appendChild(newElText)\n".
983
                "    myNode.appendChild(newEl)\n\n";
984
      }
985
    }
986

    
987
    foreach(array_keys($this->references) as $colName) {
988
      $colDef = $this->references[$colName];
989

    
990
      if(preg_match("/(ForeignKey\(')([a-zA-Z]*)/",$colDef,$matches) > 0 &&
991
         (preg_match("/Complex one2Many/",$colDef) > 0 || preg_match("/_extend/",$colName) > 0) &&
992
         preg_match("/_id/",$colName) == 0) {
993
        if(preg_match("/_extend/",$colName) == 0) {
994
          $effectiveColName = $tableRenames[$colName] == null ? $colName : $tableRenames[$colName];
995
          $def .= "    if '$matches[2]' not in usedObjectsStack:\n".
996
                  "      usedObjectsStack.append('$matches[2]')\n".
997
                  "      newEl = doc.createElement('$effectiveColName')\n".
998
                  "      newElObj = $matches[2]()\n".
999
                  "      myNode.appendChild(newElObj.exportDummyVegX(newEl,doc,usedObjectsStack))\n".
1000
                  "      usedObjectsStack.pop()\n\n";
1001
        } else {
1002
          $def .= "    if '$matches[2]' not in usedObjectsStack:\n".
1003
                  "      usedObjectsStack.append('$matches[2]')\n".
1004
                  "      newElObj = $matches[2]()\n".
1005
                  "      myNode = newElObj.exportDummyVegX(myNode,doc,usedObjectsStack)\n".
1006
                  "      usedObjectsStack.pop()\n\n";
1007
        }
1008
      }
1009
      if(preg_match("/(ManyToManyField\(')([a-zA-Z]*)/",$colDef,$matches) > 0) {
1010
        $effectiveColName = $tableRenames[$colName] == null ? $colName : $tableRenames[$colName];
1011
        $def .= "    if '$matches[2]' not in usedObjectsStack:\n".
1012
                "      usedObjectsStack.append('$matches[2]')\n".
1013
                "      newEl = doc.createElement('$effectiveColName')\n".
1014
                "      newElObj = $matches[2]()\n".
1015
                "      myNode.appendChild(newElObj.exportDummyVegX(newEl,doc,usedObjectsStack))\n".
1016
                "      usedObjectsStack.pop()\n\n";
1017
      }
1018
    }
1019

    
1020
    foreach(array_keys($this->referrers) as $nodeName) {
1021
      $colDef = $this->referrers[$nodeName];
1022
      if($nodeName == 'anyAttribute') {
1023
        $def .= "    if '$colDef' not in usedObjectsStack:\n".
1024
                "      usedObjectsStack.append('$colDef')\n".
1025
                "      newEl = doc.createAttribute(getRandomText())\n".
1026
                "      childRef = $colDef()\n".
1027
                "      myNode.setAttributeNode(childRef.exportDummyVegX(newEl,doc,usedObjectsStack))\n".
1028
                "      usedObjectsStack.pop()\n\n";
1029
      } else {
1030
        $effectiveNodeName = $tableRenames[$nodeName] == null ? $nodeName : $tableRenames[$nodeName];
1031
        $def .= "    if '$colDef' not in usedObjectsStack:\n".
1032
                "      usedObjectsStack.append('$colDef')\n\n".
1033
                "      newEl = doc.createElement('$effectiveNodeName')\n".
1034
                "      childRef = $colDef()\n".
1035
                "      myNode.appendChild(childRef.exportDummyVegX(newEl,doc,usedObjectsStack))\n".
1036
                "      usedObjectsStack.pop()\n\n";
1037
      }
1038
    }
1039

    
1040
    $def .= "    return myNode\n";
1041
    return $def;
1042
  }
1043

    
1044
  public function makeRetrieveOrNewFunction() {
1045
    global $idSysScope;
1046
    global $idExtend;
1047
    global $adHoc;
1048
    global $adHocAttr;
1049

    
1050
    $tName = $this->tableName;
1051
    $def = "  def retrieveOrNew(self,node):\n";
1052

    
1053
    if($idExtend[$tName] != '' || $idSysScope[$tName] != ''){
1054
      $extendedId = '';
1055
      if($idExtend[$tName] != '') {$extendedId = $idExtend[$tName] . "__";}
1056
      $def .= "    a_id = None\n".
1057
              "    a_system = None\n".
1058
              "    a_scope = None\n".
1059
              "    for attr in node.attributes.keys():\n".
1060
              "      aVal = node.attributes[attr].nodeValue\n".
1061
              "      if attr == 'id':\n".
1062
              "        a_id = aVal\n".
1063
              "      elif attr == 'system':\n".
1064
              "        a_system = aVal\n".
1065
              "      elif attr == 'scope':\n".
1066
              "        a_scope = aVal\n".
1067
              "    if a_id != None:\n".
1068
              "      q = $tName.objects.filter($extendedId" . "attr_id__exact = a_id)\n".
1069
              "      if a_system != None:\n".
1070
              "        q = q.filter($extendedId" . "attr_system__exact = a_system)\n".
1071
              "      if a_scope != None:\n".
1072
              "        q = q.filter($extendedId" . "attr_scope__exact = a_scope)\n".
1073
              "      if len(q) > 0:\n".
1074
              "        return q[0]\n".
1075
              "      else:\n".
1076
              "        return $tName()\n".
1077
              "    else:\n".
1078
              "      return $tName()\n";
1079
    } else if($adHoc[$tName] != '') {
1080
      $def .= handleAdHoc($tName);
1081
    } else if($adHocAttr[$tName] != '') {
1082
      $def .= handleAdHocAttr($tName);
1083
    } else {
1084
      $def .= "    return $tName()\n";
1085
    }
1086
    return $def;
1087
  }
1088

    
1089
  public function makeSetupTestFunction() {
1090
    if(isPrimitiveType($this->tableName)) { return ""; }
1091

    
1092
    $def = "  def setUp(self):\n".
1093
           "    self.impl = getDOMImplementation()\n".
1094
           "    self.newdoc = self.impl.createDocument(None, " . $this->tableName . ", None)\n".
1095
           "    top_element = newdoc.documentElement\n";
1096
  }
1097

    
1098
  public function makeImportTestFunction() {
1099
  }
1100

    
1101
  public function makeExportTestFunction() {
1102
  }
1103

    
1104
}
1105
?>
(1-1/4)