Project

General

Profile

1 3 wheeler
<?php
2
require_once('util/utilityFunctions.php');
3
require_once('objects/types.php');
4 6 wheeler
require_once('objects/lookups.php');
5 3 wheeler
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 6 wheeler
               $def == 'models.CharField(max_length=255') {
96 3 wheeler
              $def .= ", ";
97
            }
98
            $def .= "default = '$default'";
99
          }
100 6 wheeler
          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 3 wheeler
          $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 6 wheeler
              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 3 wheeler
              $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 6 wheeler
//            $this->addOneToOneReference($base . "_extend",$ref_e);
268
             $this->addOneToManyReference($base . "_extend",$ref_e,False);
269 3 wheeler
            $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 == '') {
308
      $name = $this->tableName . "_" . $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 6 wheeler
    global $nativeVegXPointers;
350
    global $manyToManyRelationships;
351 3 wheeler
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 6 wheeler
    if(isNativePointer($colName)) {
361
      $def = $nativeVegXPointers[$colName]['def'];
362
      $this->addMember($colName,$def);
363
    } else if(isPrimitiveType($typeName)) {
364 3 wheeler
      $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 6 wheeler
      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 3 wheeler
      $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 6 wheeler
        //$this->addOneToOneReference($colName,$ref_e,$optional);
399
        $this->addOneToManyReference($colName,$ref_e,False,$optional);
400 3 wheeler
      } 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 6 wheeler
        $line = 'O';
407
        if($manyToManyRelationships[$tableName][$typeName]) {
408
          $line = 'M';
409
        }
410 3 wheeler
        if(trim($line) == 'O' || trim($line) == 'o'){
411 6 wheeler
          $ref_e->addOneToManyReference($tableName . "_id",$this,False,$optional);
412 3 wheeler
          $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 6 wheeler
  public function addOneToManyReference($colName,$e,$primitiveRef = True,$optional = False) {
445 3 wheeler
    $eName = $e->getName();
446
    if($eName == $this->tableName) {
447
      $eName = 'self';
448
    }
449
    $relatedName = $this->tableName . "_" . $colName;
450 6 wheeler
    #$def = "models.OneToOneField('$eName', primary_key=True,related_name='$relatedName'";
451
    $def = "models.ForeignKey('$eName', related_name='$relatedName'";
452 3 wheeler
    if($optional) {
453
      $def .= ", null=True, blank=True";
454
    }
455
    $def .= ")";
456 6 wheeler
    if(!$primitiveRef) {
457
      $def .= " #Complex one2Many";
458
    }
459 3 wheeler
    $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
    $str = "class " . $this->tableName . "(models.Model):\n";
534
535 6 wheeler
    #All entities need reference to their creation info since
536
    #VegX does not support unique identification for all types of information,
537
    #at least not as defined in BIEN3.
538
    $str .= "  entryInfo = models.ForeignKey('EntryInfo')\n";
539
540 3 wheeler
    foreach(array_keys($this->references) as $colName) {
541
      $def = $this->references[$colName];
542
      $str .= "  $colName = $def\n";
543
    }
544
    foreach(array_keys($this->members) as $colName) {
545
      $def = $this->members[$colName];
546
      $str .= "  $colName = $def\n";
547
    }
548
549 6 wheeler
    global $geoSpatialTypes;
550
    if($geoSpatialTypes[$this->tableName]) {
551
      //Only one geometry type per table currently so this works.
552
      $geoColDef = $geoSpatialTypes[$this->tableName]['colDef'];
553
      $str .= "  \n  # GeoDjango-specific: a geometry field, and\n".
554
              "  # overriding the default manager with a GeoManager instance.\n".
555
              "  $geoColDef\n".
556
              "  objects = models.GeoManager()\n";
557
558
    }
559
560 3 wheeler
    $str .= "\n" . $this->makeExportFunction();
561
    $str .= "\n" . $this->makeImportFunction();
562
    $str .= "\n" . $this->makeExportDummyDataFunction();
563 6 wheeler
    $str .= "\n" . $this->makeRetrieveOrNewFunction();
564 3 wheeler
565
    #truncate table names that are too long for Django/Postgre to support
566
    if(strlen($this->tableName) > 54) {
567
      $tabName = 'v_' . substr($this->tableName,0,54);
568
      $str .= "\n\n  class Meta:\n".
569
              "    db_table = u'$tabName'\n\n";
570
    }
571
572
    return $str;
573
  }
574
575
  public function makeImportFunction() {
576
    #Slightly different if there are no members
577
    if(count($this->references) == 0 &&
578
       count($this->members) == 0 &&
579
       count($this->referrers) == 0) {
580 6 wheeler
      return "  def importVegX(self,node,info):\n".
581
             "    self.entryInfo = info\n".
582
             "    self.save()\n";
583 3 wheeler
    }
584
585 6 wheeler
    $def =  "  def importVegX(self,node,info):\n".
586
            "    self.entryInfo = info\n";
587 3 wheeler
588
    if(preg_match_all("/([a-zA-Z]*)_extend/",implode(",",array_keys($this->references)),$matches) > 0) {
589
      $base = $matches[1][0];
590 6 wheeler
      $def .= "    extendedEl = $base().retrieveOrNew(node)\n".
591
              "    extendedEl.importVegX(node,info)\n".
592 3 wheeler
              "    self.$base"."_extend = extendedEl\n\n";
593
    }
594
595
    $def .= "    self.save()\n";
596
597
    #Fun hack for anyAttribute & anyNode nodes
598
    if(preg_match("/_any_attr/",$this->tableName,$matches) > 0 ||
599
       preg_match("/_any_nodes/",$this->tableName,$matches) > 0) {
600
      return $def;
601
    }
602
603
    if(preg_match("/attr_/",implode(",",array_keys($this->members))) > 0 ||
604
       preg_match("/anyAttribute/",implode(",",array_keys($this->referrers))) > 0) {
605
      $def .= "    #attributes\n".
606
              "    for attr in node.attributes.keys():\n".
607
              "      aName = 'attr_' + attr\n".
608
              "      aVal = node.attributes[attr].nodeValue\n";
609
      $i = 0;
610
      foreach(array_keys($this->members) as $colName) {
611
        $ifStmt = $i == 0 ? 'if' : 'elif';
612
        if(preg_match("/^attr_/",$colName,$matches) > 0) {
613
          $i += 1;
614
          if(preg_match("/BooleanField/",$this->members[$colName],$matches) > 0) {
615
            $def .= "      $ifStmt aName == '$colName' and (aVal == 'true' or\n".
616
                    "      aVal == 'false' or aVal == 0 or aVal == 1):\n".
617
                    "        self.$colName = (aVal == 'true' or aVal == 1)\n";
618
          } else {
619
            $def .= "      $ifStmt aName == '$colName':\n".
620
                    "        self.$colName = aVal\n";
621
          }
622
        }
623
      }
624
    }
625
    if(preg_match("/anyAttribute/",implode(",",array_keys($this->referrers))) > 0) {
626
      $type = $this->referrers['anyAttribute'];
627
      $tIDName = $this->tableName . "_id";
628
      if(preg_match_all("/attr_/",implode(",",array_keys($this->members)),$matches) > 0) {
629
        $def .= "      else:\n".
630
                "        newEl = $type()\n".
631
                "        newEl.$tIDName = self\n".
632
                "        newEl.attr_name = attr\n".
633
                "        newEl.attr_value = aVal\n".
634 6 wheeler
                "        newEl.entryInfo = info\n".
635 3 wheeler
                "        newEl.save()\n";
636
      } else {
637
        $def .= "      newEl = $type()\n".
638
                "      newEl.$tIDName = self\n".
639
                "      newEl.attr_name = attr\n".
640
                "      newEl.attr_value = aVal\n".
641 6 wheeler
                "      newEl.entryInfo = info\n".
642 3 wheeler
                "      newEl.save()\n";
643
      }
644
    }
645
646
    if(count($this->members) -
647
       preg_match_all("/attr_/",implode(",",array_keys($this->members)),$matches) -
648
       preg_match_all("/primitive_type_value/",implode(",",array_keys($this->members)),$matches) > 0 ||
649
       count($this->references) > 0 || count($this->referrers) > 0) {
650
      $def .= "    #members & relationships\n".
651
              "    for child in node.childNodes:\n".
652
              "      cName = child.nodeName\n";
653
    }
654
655
    $i = 0;
656
    if(count($this->members) -
657
       preg_match_all("/attr_/",implode(",",array_keys($this->members)),$matches) -
658
       preg_match_all("/primitive_type_value/",implode(",",array_keys($this->members)),$matches) > 0) {
659
      foreach(array_keys($this->members) as $colName) {
660
        if(preg_match("/^attr_/",$colName) > 0) { continue; }
661 6 wheeler
        else if(isNativePointer($colName)) {
662
          global $nativeVegXPointers;
663
          $ifStmt = $i == 0 ? 'if' : 'elif';
664
          $i += 1;
665
          $tabType = $nativeVegXPointers[$colName]['fk_type'];
666
          $toField = $nativeVegXPointers[$colName]['to_field'];
667
          $def .= "      $ifStmt cName == '$colName':\n".
668
                  "        if(len(child.childNodes) > 0):\n".
669
                  "          cVal = child.childNodes[0].nodeValue\n".
670
                  "          q = $tabType.objects.filter($toField" . "__exact = cVal)\n".
671
                  "          q = $tabType.objects.filter(entryInfo__id__exact = self.entryInfo.id)\n".
672
                  "          if len(q) > 0:\n".
673
                  "            self.$colName = q[0]\n";
674
        } else {
675
          $ifStmt = $i == 0 ? 'if' : 'elif';
676
          $i += 1;
677
          $def .= "      $ifStmt cName == '$colName':\n".
678
                  "        if(len(child.childNodes) > 0):\n".
679
                  "          cVal = child.childNodes[0].nodeValue\n".
680
                  "          self.$colName = cVal\n";
681
        }
682 3 wheeler
      }
683
    }
684
685
    if(preg_match_all("/primitive_type_value/",implode(",",array_keys($this->members)),$matches) > 0) {
686 6 wheeler
      $def .= "    if(len(node.childNodes) > 0):\n".
687
              "      cVal = node.childNodes[0].nodeValue\n".
688
              "      self.primitive_type_value = cVal\n";
689 3 wheeler
    }
690
691
    foreach(array_keys($this->references) as $colName) {
692
      $ifStmt = $i == 0 ? 'if' : 'elif';
693
      $colDef = $this->references[$colName];
694
695
      if(preg_match("/(ForeignKey\(')([a-zA-Z]*)/",$colDef,$matches) > 0 &&
696 6 wheeler
         preg_match("/Complex one2Many/",$colDef) > 0 && preg_match("/_extend/",$colDef) == 0) {
697 3 wheeler
        $i += 1;
698
        $def .= "      $ifStmt cName == '$colName':\n".
699 6 wheeler
                "        newEl = $matches[2]().retrieveOrNew(child)\n".
700
                "        newEl.importVegX(child,info)\n".
701 3 wheeler
                "        self.$colName = newEl\n";
702
      }
703
      if(preg_match("/(ManyToManyField\(')([a-zA-Z]*)/",$colDef,$matches) > 0) {
704
        $i += 1;
705
        $def .= "      $ifStmt cName == '$colName':\n".
706 6 wheeler
                "        newEl = $matches[2]().retrieveOrNew(child)\n".
707
                "        newEl.importVegX(child,info)\n".
708 3 wheeler
                "        self.$colName.add(newEl)\n";
709
      }
710
    }
711
712
    if(count($this->referrers) > 0) {
713
      $def .= "      #These are the elements that refer to this one\n";
714
    }
715
    $allowAnyNode = False;
716
    foreach(array_keys($this->referrers) as $colName) {
717
      if($colName == 'anyAttribute' || $colName == 'anyNode') { continue; }
718
      $ifStmt = $i == 0 ? 'if' : 'elif';
719
      $i += 1;
720
      $colDef = $this->referrers[$colName];
721
      $elReferenceBack = $this->tableName . '_id';
722
      $def .= "      $ifStmt cName == '$colName':\n".
723 6 wheeler
              "        newEl = $colDef().retrieveOrNew(child)\n".
724 3 wheeler
              "        newEl.$elReferenceBack = self\n".
725 6 wheeler
              "        newEl.importVegX(child,info)\n";
726 3 wheeler
    }
727
    if(preg_match("/anyNode/",implode(",",array_keys($this->referrers))) > 0) {
728
      $type = $this->referrers['anyNode'];
729
      $tIDName = $this->tableName . "_id";
730
      if($i > 0) {
731
        $def .= "      else:\n".
732
                "        newEl = $type()\n".
733
                "        newEl.$tIDName = self\n".
734
                "        newEl.node_name = cName\n".
735
                "        for grandchild in child.childNodes:\n".
736
                "          newEl.node_value += grandchild.toxml()\n".
737 6 wheeler
                "        newEl.entryInfo = info\n".
738 3 wheeler
                "        newEl.save()\n";
739
      } else {
740
        $def .= "      newEl = $type()\n".
741
                "      newEl.$tIDName = self\n".
742
                "      newEl.node_name = cName\n".
743
                "      for grandchild in child.childNodes:\n".
744
                "        newEl.node_value += grandchild.toxml()\n".
745 6 wheeler
                "      newEl.entryInfo = info\n".
746 3 wheeler
                "      newEl.save()\n";
747
      }
748
    }
749
750 6 wheeler
    global $geoSpatialTypes;
751
    if($geoSpatialTypes[$this->tableName]) {
752
      //Only one geometry type per table currently so this works.
753
      $geoColImportDef = $geoSpatialTypes[$this->tableName]['importDef'];
754
      $def .= "  \n    # Convert to geometry types to make use of GeoDjango's\n".
755
              "    # capabilities.\n".
756
              "  $geoColImportDef\n";
757
758
    }
759
760 3 wheeler
    $def .= "\n    self.save()\n";
761
    return $def;
762
763
  }
764
765
  public function makeExportFunction() {
766
    #Slightly different if there are no members
767
    if(count($this->references) == 0 &&
768
       count($this->members) == 0 &&
769
       count($this->referrers) == 0) {
770
      return "  def exportVegX(self,myNode,doc):\n".
771
             "    return myNode\n";
772
    }
773
774
    $def =  "  def exportVegX(self,myNode,doc):\n";
775
776
    #Fun hack for anyAttribute & anyNode nodes
777
    if(preg_match("/_any_attr/",$this->tableName,$matches) > 0) {
778
      $def .= "    newAttr = doc.createAttribute(self.attr_name)\n".
779
              "    newAttr.value = self.attr_value\n".
780
              "    return newAttr\n";
781
      return $def;
782
    }
783
    if(preg_match("/_any_nodes/",$this->tableName,$matches) > 0) {
784
      $def .= "    newEl = doc.createElement(self.node_name)\n".
785
              "    newElText = doc.createTextNode(self.node_value)\n".
786
              "    newEl.appendChild(newElText)\n".
787
              "    return newEl\n\n";
788
      return $def;
789
    }
790
791
    foreach(array_keys($this->members) as $colName) {
792
      $nodeName = $colName;
793
      $nodeText = "str(self.$colName)";
794
      //Python's string representation of booleans is True/False but xsd requires
795
      //true/false (lowercase) so we need this hack.
796
      if(preg_match("/NullBooleanField/",$this->members[$colName],$matches) > 0) {
797
        $nodeText = "string.lower(str(self.$colName))";
798
      }
799
      if(preg_match("/^attr_/",$colName,$matches) > 0) {
800
        $nodeName = preg_replace("/^attr_/","",$colName);
801
        $def .= "    if self.$colName != None:\n".
802
                "      newAttr = doc.createAttribute('$nodeName')\n".
803
                "      newAttr.value = $nodeText\n".
804
                "      myNode.setAttributeNode(newAttr)\n\n";
805
      } else if(preg_match("/primitive_type_value/",$colName,$matches) > 0) {
806
        $def .= "    if self.$colName != None:\n".
807
                "      newElText = doc.createTextNode(self.$colName)\n".
808
                "      myNode.appendChild(newElText)\n\n";
809 6 wheeler
      }else if(isNativePointer($colName)) {
810
        global $nativeVegXPointers;
811
        $to_field = $nativeVegXPointers[$colName]['to_field'];
812
        $nodeText = "str(self.$colName.$to_field)";
813
        $def .= "    if self.$colName != None:\n".
814
                "      newEl = doc.createElement('$colName')\n".
815
                "      newElText = doc.createTextNode($nodeText)\n".
816
                "      newEl.appendChild(newElText)\n".
817
                "      myNode.appendChild(newEl)\n\n";
818 3 wheeler
      }else {
819
/*
820
        if(preg_match("/DateField/",$this->members[$colName],$matches) > 0 ||
821
           preg_match("/TimeField/",$this->members[$colName],$matches) > 0 ||
822
           preg_match("/PositiveIntegerField/",$this->members[$colName],$matches) > 0 ||
823
           preg_match("/NullBooleanField/",$this->members[$colName],$matches) > 0 ||
824
           preg_match("/FloatField/",$this->members[$colName],$matches) > 0) {
825
          $nodeText = "str(self.$colName)";
826
        }
827
*/
828
        $def .= "    if self.$colName != None:\n".
829
                "      newEl = doc.createElement('$colName')\n".
830
                "      newElText = doc.createTextNode($nodeText)\n".
831
                "      newEl.appendChild(newElText)\n".
832
                "      myNode.appendChild(newEl)\n\n";
833
      }
834
    }
835
836
    foreach(array_keys($this->references) as $colName) {
837
      $colDef = $this->references[$colName];
838
839
      if(preg_match("/(ForeignKey\(')([a-zA-Z]*)/",$colDef,$matches) > 0 &&
840 6 wheeler
         (preg_match("/Complex one2Many/",$colDef) > 0 || preg_match("/_extend/",$colName) > 0)) {
841 3 wheeler
        if(preg_match("/_extend/",$colName) == 0) {
842
          $def .= "    if self.$colName != None:\n".
843
                  "      newEl = doc.createElement('$colName')\n".
844
                  "      myNode.appendChild(self.$colName.exportVegX(newEl,doc))\n\n";
845
        } else {
846
          $def .= "    if self.$colName != None:\n".
847
                  "      myNode = self.$colName.exportVegX(myNode,doc)\n\n";
848
        }
849
      }
850
      if(preg_match("/(ManyToManyField\(')([a-zA-Z]*)/",$colDef,$matches) > 0) {
851
        $def .= "    for childRef in self.$colName.all():\n".
852
                "      newEl = doc.createElement('$colName')\n".
853
                "      myNode.appendChild(childRef.exportVegX(newEl,doc))\n\n";
854
      }
855
    }
856
857
    foreach(array_keys($this->referrers) as $nodeName) {
858
      $nodeNameToUse = $nodeName;
859
      if($nodeName == 'anyAttribute') {
860
        $nodeNameToUse = 'any_attr';
861
        $relatedName = $this->tableName . '_' . $nodeNameToUse . '_' . $this->tableName . '_id';
862
        $def .= "    for childRef in self.$relatedName.all():\n".
863
                "      newEl = doc.createAttribute('$nodeName')\n".
864
                "      myNode.setAttributeNode(childRef.exportVegX(newEl,doc))\n\n";
865
      } else {
866
        if($nodeName == 'anyNode') {
867
          $nodeNameToUse = 'any_nodes';
868
        }
869
        $relatedName = $this->tableName . '_' . $nodeNameToUse . '_' . $this->tableName . '_id';
870
        $def .= "    for childRef in self.$relatedName.all():\n".
871
                "      newEl = doc.createElement('$nodeName')\n".
872
                "      myNode.appendChild(childRef.exportVegX(newEl,doc))\n\n";
873
      }
874
    }
875
876
    $def .= "    return myNode\n";
877
    return $def;
878
  }
879
880
  public function makeExportDummyDataFunction() {
881
    #Slightly different if there are no members
882
    if(count($this->references) == 0 &&
883
       count($this->members) == 0 &&
884
       count($this->referrers) == 0) {
885
      return "  def exportDummyVegX(self,myNode,doc,usedObjectsStack):\n".
886
             "    return myNode\n";
887
    }
888
889
    $def =  "  def exportDummyVegX(self,myNode,doc,usedObjectsStack):\n";
890
891
    #Fun hack for anyAttribute & anyNode nodes
892
    if(preg_match("/_any_attr/",$this->tableName,$matches) > 0) {
893
      $def .= "    newAttr = doc.createAttribute(getRandomString())\n".
894
              "    newAttr.value = getRandomString()\n".
895
              "    return newAttr\n";
896
      return $def;
897
    }
898
    if(preg_match("/_any_nodes/",$this->tableName,$matches) > 0) {
899
      $def .= "    newEl = doc.createElement(getRandomString())\n".
900
              "    newElText = doc.createTextNode(getRandomText())\n".
901
              "    newEl.appendChild(newElText)\n".
902
              "    return newEl\n\n";
903
      return $def;
904
    }
905
906
    foreach(array_keys($this->members) as $colName) {
907
      $nodeName = $colName;
908
      $colDef = $this->members[$colName];
909
      $randomFun = "getRandomString";
910
      if(preg_match("/FloatField/",$colDef,$matches) > 0) {
911
        $randomFun = "getRandomFloat";
912
      } else if(preg_match("/IntegerField/",$colDef,$matches) > 0) {
913
        $randomFun = "getRandomInt";
914
      } else if(preg_match("/TextField/",$colDef,$matches) > 0) {
915
        $randomFun = "getRandomText";
916
      } else if(preg_match("/DateField/",$colDef,$matches) > 0) {
917
        $randomFun = "getRandomDate";
918
      } else if(preg_match("/TimeField/",$colDef,$matches) > 0) {
919
        $randomFun = "getRandomTime";
920
      } else if(preg_match("/NullBooleanField/",$colDef,$matches) > 0) {
921
        $randomFun = "getRandomBool";
922
      }
923
924
      #Need to explicitly convert to string so minidom doesn't
925
      #roll over in nasty convulsions
926
      $randomFun = "str($randomFun())";
927 6 wheeler
928 3 wheeler
      if(preg_match("/^attr_/",$colName,$matches) > 0) {
929
        $nodeName = preg_replace("/^attr_/","",$colName);
930
        $def .= "    newAttr = doc.createAttribute('$nodeName')\n".
931
                "    newAttr.value = $randomFun\n".
932
                "    myNode.setAttributeNode(newAttr)\n\n";
933
      } else if(preg_match("/primitive_type_value/",$colName,$matches) > 0) {
934
        $def .= "    newElText = doc.createTextNode($randomFun)\n".
935
                "    myNode.appendChild(newElText)\n\n";
936
      }else {
937
        $def .= "    newEl = doc.createElement('$colName')\n".
938
                "    newElText = doc.createTextNode($randomFun)\n".
939
                "    newEl.appendChild(newElText)\n".
940
                "    myNode.appendChild(newEl)\n\n";
941
      }
942
    }
943
944
    foreach(array_keys($this->references) as $colName) {
945
      $colDef = $this->references[$colName];
946
947
      if(preg_match("/(ForeignKey\(')([a-zA-Z]*)/",$colDef,$matches) > 0 &&
948 6 wheeler
         (preg_match("/Complex one2Many/",$colDef) > 0 || preg_match("/_extend/",$colName) > 0)) {
949 3 wheeler
        if(preg_match("/_extend/",$colName) == 0) {
950
          $def .= "    if '$matches[2]' not in usedObjectsStack:\n".
951
                  "      usedObjectsStack.append('$matches[2]')\n".
952
                  "      newEl = doc.createElement('$colName')\n".
953
                  "      newElObj = $matches[2]()\n".
954
                  "      myNode.appendChild(newElObj.exportDummyVegX(newEl,doc,usedObjectsStack))\n".
955
                  "      usedObjectsStack.pop()\n\n";
956
        } else {
957
          $def .= "    if '$matches[2]' not in usedObjectsStack:\n".
958
                  "      usedObjectsStack.append('$matches[2]')\n".
959
                  "      newElObj = $matches[2]()\n".
960
                  "      myNode = newElObj.exportDummyVegX(myNode,doc,usedObjectsStack)\n".
961
                  "      usedObjectsStack.pop()\n\n";
962
        }
963
      }
964
      if(preg_match("/(ManyToManyField\(')([a-zA-Z]*)/",$colDef,$matches) > 0) {
965
        $def .= "    if '$matches[2]' not in usedObjectsStack:\n".
966
                "      usedObjectsStack.append('$matches[2]')\n".
967
                "      newEl = doc.createElement('$colName')\n".
968
                "      newElObj = $matches[2]()\n".
969
                "      myNode.appendChild(newElObj.exportDummyVegX(newEl,doc,usedObjectsStack))\n".
970
                "      usedObjectsStack.pop()\n\n";
971
      }
972
    }
973
974
    foreach(array_keys($this->referrers) as $nodeName) {
975
      $colDef = $this->referrers[$nodeName];
976
      if($nodeName == 'anyAttribute') {
977
        $def .= "    if '$colDef' not in usedObjectsStack:\n".
978
                "      usedObjectsStack.append('$colDef')\n".
979
                "      newEl = doc.createAttribute(getRandomText())\n".
980
                "      childRef = $colDef()\n".
981
                "      myNode.setAttributeNode(childRef.exportDummyVegX(newEl,doc,usedObjectsStack))\n".
982
                "      usedObjectsStack.pop()\n\n";
983
      } else {
984
        $def .= "    if '$colDef' not in usedObjectsStack:\n".
985
                "      usedObjectsStack.append('$colDef')\n\n".
986
                "      newEl = doc.createElement('$nodeName')\n".
987
                "      childRef = $colDef()\n".
988
                "      myNode.appendChild(childRef.exportDummyVegX(newEl,doc,usedObjectsStack))\n".
989
                "      usedObjectsStack.pop()\n\n";
990
      }
991
    }
992
993
    $def .= "    return myNode\n";
994
    return $def;
995
  }
996
997 6 wheeler
  public function makeRetrieveOrNewFunction() {
998
    global $idSysScope;
999
    global $idExtend;
1000
    global $adHoc;
1001
    global $adHocAttr;
1002
1003
    $tName = $this->tableName;
1004
    $def = "  def retrieveOrNew(self,node):\n";
1005
1006
    if($idExtend[$tName] != '' || $idSysScope[$tName] != ''){
1007
      $extendedId = '';
1008
      if($idExtend[$tName] != '') {$extendedId = $idExtend[$tName] . "__";}
1009
      $def .= "    a_id = None\n".
1010
              "    a_system = None\n".
1011
              "    a_scope = None\n".
1012
              "    for attr in node.attributes.keys():\n".
1013
              "      aVal = node.attributes[attr].nodeValue\n".
1014
              "      if attr == 'id':\n".
1015
              "        a_id = aVal\n".
1016
              "      elif attr == 'system':\n".
1017
              "        a_system = aVal\n".
1018
              "      elif attr == 'scope':\n".
1019
              "        a_scope = aVal\n".
1020
              "    if a_id != None:\n".
1021
              "      q = $tName.objects.filter($extendedId" . "attr_id__exact = a_id)\n".
1022
              "      if a_system != None:\n".
1023
              "        q = q.filter($extendedId" . "attr_system__exact = a_system)\n".
1024
              "      if a_scope != None:\n".
1025
              "        q = q.filter($extendedId" . "attr_scope__exact = a_scope)\n".
1026
              "      if len(q) > 0:\n".
1027
              "        return q[0]\n".
1028
              "      else:\n".
1029
              "        return $tName()\n".
1030
              "    else:\n".
1031
              "      return $tName()\n";
1032
    } else if($adHoc[$tName] != '') {
1033
      $def .= handleAdHoc($tName);
1034
    } else if($adHocAttr[$tName] != '') {
1035
      $def .= handleAdHocAttr($tName);
1036
    } else {
1037
      $def .= "    return $tName()\n";
1038
    }
1039
    return $def;
1040
  }
1041
1042 3 wheeler
  public function makeSetupTestFunction() {
1043
    if(isPrimitiveType($this->tableName)) { return ""; }
1044
1045
    $def = "  def setUp(self):\n".
1046
           "    self.impl = getDOMImplementation()\n".
1047
           "    self.newdoc = self.impl.createDocument(None, " . $this->tableName . ", None)\n".
1048
           "    top_element = newdoc.documentElement\n";
1049
  }
1050
1051
  public function makeImportTestFunction() {
1052
  }
1053
1054
  public function makeExportTestFunction() {
1055
  }
1056
1057
}
1058
?>