Core  3.2
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
Class.Form1NF.php
Go to the documentation of this file.
1 <?php
2 /*
3  * @author Anakeen
4  * @package FDL
5 */
6 /**
7  * Export 1NF class
8  *
9  * @author Anakeen
10  * @version $Id: $
11  * @package FDL
12  */
13 /**
14  */
15 
16 include_once ("FDL/Class.SearchDoc.php");
17 /*
18  * foreach($this->doc->fields as $k=>$v) {
19  if (is_numeric($k)) $props[$v] = $this->doc->$v;
20  }
21  *
22  *
23  * $this->infofields
24  *
25  *
26  * select max(id) from docread where initid=%initid%
27 */
28 /**
29  *
30  */
31 class Form1NF
32 {
33  /**
34  * Parameters
35  * @var array
36  */
37  private $params = array(
38  'config' => '', // XML config file name
39  'outputsql' => '', // output file name
40  'outputpgservice' => '', // output pgservice name
41  'tmppgservice' => 'tmp_1nf', // temporary pg service
42  'tmpschemaname' => '1nf', // temporary schema name
43  'tmpemptydb' => 'yes', // whether the process empty the database before process
44  'sqllog' => '', // SQL log file
45 
46  );
47  /**
48  *
49  * @var string
50  */
51  private $sqlStandardLogHandle = null;
52  /**
53  *
54  * @var int
55  */
56  private $sqlStandardLogCounter = 0;
57  /**
58  *
59  * @var int
60  */
61  private $sqlStandardLogBufferSize = 300;
62  /**
63  *
64  * @var string
65  */
66  private $sqlStandardLogBuffer = '';
67  /**
68  *
69  * @var string
70  */
71  private $sqlPostgresLogHandle = null;
72  /**
73  *
74  * @var string
75  */
76  private $sqlPostgresFileName = '';
77  /**
78  *
79  * @var int
80  */
81  private $sqlPostgresLogCounter = 0;
82  /**
83  *
84  * @var int
85  */
86  private $sqlPostgresLogBufferSize = 300;
87  /**
88  *
89  * @var string
90  */
91  private $sqlPostgresLogBuffer = '';
92  /**
93  *
94  * @var array
95  */
96  private $sqlSequences = array();
97  /**
98  *
99  * @var int
100  */
101  private $sqlInsertCounter = 0;
102  /**
103  *
104  * @var array
105  */
106  private $sqlInsertBuffer = array();
107  /**
108  *
109  * @var int
110  */
111  private $sqlInsertBufferSize = 300;
112  /**
113  *
114  * @var array
115  */
116  public $dropSchemas = array(
117  'public',
118  'dav',
119  'family'
120  );
121  /**
122  *
123  * @var string
124  */
125  public $freedom_pgservice = null;
126  /**
127  *
128  * @var string
129  */
130  public $freedom_dbaccess = null;
131  /**
132  * Action
133  * @var Action
134  */
135  public $action = null;
136  /**
137  * Error message
138  * @var string
139  */
140  public $errmsg = '';
141  /**
142  *
143  * @var array[int]Form1NF_Table
144  */
145  private $config = array();
146  /**
147  *
148  * @var resource
149  */
150  private $conn = null;
151  /**
152  *
153  * @var resource
154  */
155  private $tmp_conn = null;
156  /**
157  *
158  * @var string
159  */
160  public $tmp_dbaccess = null;
161  /**
162  *
163  * @param array $params
164  */
165  public function __construct($params)
166  {
167  global $action;
168  $this->action = $action;
169  foreach ($params as $key => $value) {
170  if (array_key_exists($key, $this->params)) {
171  $this->params[$key] = $value;
172  }
173  }
174 
175  $this->freedom_dbaccess = $action->dbaccess;
176  if ($this->freedom_dbaccess == "") {
177  $action->error(_("Error: empty action->dbaccess"));
178  }
179  $this->freedom_pgservice = getServiceFreedom();
180 
181  $this->tmp_dbaccess = sprintf("service=%s", $this->params['tmppgservice']);
182  }
183  /**
184  *
185  * @param mixed $value
186  * @return string;
187  */
188  private function getPgEscape($value, $nullAllowed = true)
189  {
190  if ($nullAllowed && "$value" === "") return 'NULL';
191  return "'" . pg_escape_string($value) . "'";
192  }
193  /**
194  *
195  * @param mixed $value
196  * @return string;
197  */
198  private function getPgEscapeCopy($value, $nullAllowed = true)
199  {
200  if ($nullAllowed && "$value" === "") return "\\N";
201  $value = pg_escape_string($value);
202  $value = str_replace(array(
203  "\r",
204  "\n",
205  "\t"
206  ) , array(
207  "\\r",
208  "\\n",
209  "\\t"
210  ) , $value);
211  return $value;
212  }
213  /**
214  *
215  */
216  private function stdInfo()
217  {
218  $args = func_get_args();
219  if (count($args) >= 2) {
220  $msg = call_user_func_array('sprintf', $args);
221  } else {
222  $msg = $args[0];
223  }
224  $this->action->info(trim($msg));
225  }
226  /**
227  *
228  */
229  private function stdError()
230  {
231  $args = func_get_args();
232  if (count($args) >= 2) {
233  $msg = call_user_func_array('sprintf', $args);
234  } else {
235  $msg = $args[0];
236  }
237  $this->action->error(trim($msg));
238  $this->sqlLogWrite($msg, true);
239  $this->sqlLogFlush();
240  //debug_print_backtrace();
241  throw new Dcp\Exception(trim($msg));
242  }
243  /**
244  *
245  */
246  private function sqlLogFlush()
247  {
248  $this->sqlPostgresLogFlush();
249  $this->sqlStandardLogFlush();
250  return true;
251  }
252  /**
253  *
254  */
255  private function sqlLogOpen()
256  {
257  if (!$this->sqlPostgresLogOpen()) return false;
258  if (!$this->sqlStandardLogOpen()) return false;
259  return true;
260  }
261  /**
262  *
263  */
264  private function sqlLogClose()
265  {
266  if (!$this->sqlPostgresLogClose()) return false;
267  if (!$this->sqlStandardLogClose()) return false;
268  return true;
269  }
270  /**
271  *
272  */
273  private function sqlLogWrite($line, $comment = false)
274  {
275  $this->sqlPostgresLogWrite($line, $comment);
276  $this->sqlStandardLogWrite($line, $comment);
277  }
278  /**
279  *
280  */
281  private function sqlStandardLogFlush()
282  {
283  if ($this->sqlStandardLogHandle !== null) {
284  @fwrite($this->sqlStandardLogHandle, $this->sqlStandardLogBuffer);
285  $this->sqlStandardLogBuffer = '';
286  $this->sqlStandardLogCounter = 0;
287  }
288  }
289  /**
290  *
291  */
292  private function sqlStandardLogWrite($line, $comment = false, $comma = true)
293  {
294  if ($this->sqlStandardLogHandle !== null) {
295  if ($comment) {
296  $line = "\n--\n-- " . str_replace("\n", "\n-- ", str_replace("\r", "", $line)) . "\n--\n";
297  } elseif ($comma && substr($line, -1) != ';') {
298  $line.= ';';
299  }
300  $line = str_replace('"' . $this->params['tmpschemaname'] . '".', '', $line) . "\n";
301  $this->sqlStandardLogBuffer.= $line;
302  $this->sqlStandardLogCounter++;
303  if ($this->sqlStandardLogCounter >= $this->sqlStandardLogBufferSize) {
304  $this->sqlStandardLogFlush();
305  }
306  }
307  }
308  /**
309  *
310  */
311  private function sqlStandardLogClose()
312  {
313  if ($this->sqlStandardLogHandle !== null) {
314  $this->sqlStandardLogFlush();
315  @fwrite($this->sqlStandardLogHandle, "\n\n\n");
316  @fclose($this->sqlStandardLogHandle);
317  }
318  return true;
319  }
320  /**
321  *
322  */
323  private function sqlStandardLogOpen()
324  {
325  try {
326  if (!empty($this->params['outputsql'])) {
327  $this->sqlStandardLogHandle = @fopen($this->params['outputsql'], 'w');
328  if (!$this->sqlStandardLogHandle) {
329  $this->stdError(_("Error could not open output log file '%s' for writing.") , $this->params['outputsql']);
330  }
331  }
332  }
333  catch(Exception $e) {
334  return false;
335  }
336  return true;
337  }
338  /**
339  *
340  */
341  private function sqlPostgresLogFlush()
342  {
343  if ($this->sqlPostgresLogHandle !== null) {
344  @fwrite($this->sqlPostgresLogHandle, $this->sqlPostgresLogBuffer);
345  $this->sqlPostgresLogBuffer = '';
346  $this->sqlPostgresLogCounter = 0;
347  }
348  }
349  /**
350  *
351  */
352  private function sqlPostgresLogWrite($line, $comment = false, $comma = true)
353  {
354  if ($this->sqlPostgresLogHandle !== null) {
355  if ($comment) {
356  $line = "\n--\n-- " . str_replace("\n", "\n-- ", str_replace("\r", "", $line)) . "\n--\n";
357  } elseif ($comma && substr($line, -1) != ';') {
358  $line.= ';';
359  }
360  $line = str_replace('"' . $this->params['tmpschemaname'] . '".', '', $line) . "\n";
361  $this->sqlPostgresLogBuffer.= $line;
362  $this->sqlPostgresLogCounter++;
363  if ($this->sqlPostgresLogCounter >= $this->sqlPostgresLogBufferSize) {
364  $this->sqlPostgresLogFlush();
365  }
366  }
367  }
368  /**
369  *
370  */
371  private function sqlPostgresLogClose()
372  {
373  if ($this->sqlPostgresLogHandle !== null) {
374  $this->sqlPostgresLogFlush();
375  @fwrite($this->sqlPostgresLogHandle, "\n\n\n");
376  @fclose($this->sqlPostgresLogHandle);
377  }
378  return true;
379  }
380  /**
381  *
382  */
383  private function sqlPostgresLogOpen()
384  {
385  include_once ('WHAT/Lib.Common.php');
386 
387  try {
388  if (!empty($this->params['outputpgservice']) || !empty($this->params['sqllog'])) {
389  if (empty($this->params['sqllog'])) {
390  $this->sqlPostgresFileName = tempnam(getTmpDir() , 'sqlPostgres.tmp.1nf.');
391  if ($this->sqlPostgresFileName === false) {
392  $this->stdError(_("Error creating temp file for sql log output."));
393  }
394  } else {
395  $this->sqlPostgresFileName = $this->params['sqllog'];
396  }
397 
398  $this->sqlPostgresLogHandle = @fopen($this->sqlPostgresFileName, 'w');
399  if (!$this->sqlPostgresLogHandle) {
400  $this->stdError(_("Error could not open sql log file '%s' for writing.") , $this->sqlPostgresFileName);
401  }
402  }
403  }
404  catch(Exception $e) {
405  return false;
406  }
407  return true;
408  }
409  /**
410  *
411  * @return bool
412  */
413  public function run()
414  {
415 
416  try {
417  // parse xml config
418  if (!$this->configParse()) return false;
419  // check freedom connection
420  if (!$this->freedomDatabaseConnection()) return false;
421  // check tmp connection
422  if (!$this->tmpDatabaseConnection()) return false;
423  // whether to empty tmp db or not
424  if ($this->params['tmpemptydb'] == 'yes') {
425  // empty database
426  if (!$this->tmpDatabaseEmpty()) return false;
427  // dump freedom
428  $dumpFile = $this->databaseDump($this->freedom_pgservice);
429  if ($dumpFile === false) return false;
430  // load dump into tmp
431  if (!$this->databaseLoad($dumpFile, $this->params['tmppgservice'])) return false;
432  // delete dump file
433  @unlink($dumpFile);
434  }
435  // open log file
436  if (!$this->sqlLogOpen()) return false;
437  // load config
438  if (!$this->configLoad()) return false;
439  // create temporary schema
440  if (!$this->sqlCreateSchema()) return false;
441  // create tables
442  if (!$this->sqlCreateTables()) return false;
443  // fill tables
444  if (!$this->sqlFillTables()) return false;
445  // make references
446  if (!$this->sqlMakeReferences()) return false;
447  // close log file
448  if (!$this->sqlLogClose()) return false;
449  // output management
450  if (!empty($this->params['outputpgservice'])) {
451  if (!$this->databaseLoad($this->sqlPostgresFileName, $this->params['outputpgservice'])) return false;
452  }
453  // temporary file
454  if (!empty($this->sqlPostgresFileName) && empty($this->params['sqllog'])) {
455  @unlink($this->sqlPostgresFileName);
456  }
457  }
458  catch(Exception $e) {
459  return false;
460  }
461 
462  $this->stdInfo(_("Export 1NF done"));
463  return true;
464  }
465  /**
466  *
467  * @param mixed $requests
468  * @return bool
469  */
470  private function sqlExecute($requests, $log = true)
471  {
472  if (!is_array($requests)) {
473  $requests = array(
474  $requests
475  );
476  }
477  foreach ($requests as $sql) {
478  if (preg_match("/^\s*--/", $sql)) {
479  continue;
480  }
481  if ($log) $this->sqlLogWrite($sql);
482  $res = @pg_query($this->tmp_conn, $sql);
483  if (!$res) $this->checkErrorPostgresql($sql);
484  }
485  return true;
486  }
487  /**
488  *
489  * @param mixed $requests
490  * @return bool
491  */
492  private function sqlInsertFlush()
493  {
494  foreach ($this->sqlInsertBuffer as $tableName => $rows) {
495  $sql = 'COPY "' . $this->params['tmpschemaname'] . '"."' . $tableName . '" FROM STDIN;';
496  $this->sqlPostgresLogWrite($sql, false, false);
497  $res = @pg_query($this->tmp_conn, $sql);
498  if (!$res) $this->checkErrorPostgresql($sql);
499  foreach ($rows as $row) {
500  $this->sqlPostgresLogWrite($row, false, false);
501  $res = @pg_put_line($this->tmp_conn, $row . "\n");
502  if (!$res) $this->checkErrorPostgresql("ROW $row");
503  }
504  $this->sqlPostgresLogWrite("\\.\n", false, false);
505  $res = @pg_put_line($this->tmp_conn, "\\.\n");
506  if (!$res) $this->checkErrorPostgresql();
507  $res = @pg_end_copy($this->tmp_conn);
508  if (!$res) $this->checkErrorPostgresql();
509  }
510  $this->sqlInsertBuffer = array();
511  $this->sqlInsertCounter = 0;
512  }
513  /**
514  *
515  * @param mixed $requests
516  * @return bool
517  */
518  private function sqlInsert($table, $fields, $values, $escapedValues)
519  {
520  $this->sqlStandardLogWrite('INSERT INTO "' . $this->params['tmpschemaname'] . '"."' . $table . '" ("' . implode('","', $fields) . '") VALUES (' . implode(',', $escapedValues) . ');');
521 
522  if (!isset($this->sqlInsertBuffer[$table])) {
523  $this->sqlInsertBuffer[$table] = array();
524  }
525  $this->sqlInsertBuffer[$table][] = implode("\t", $values);
526  $this->sqlInsertCounter++;
527 
528  if ($this->sqlInsertCounter >= $this->sqlInsertBufferSize) {
529  $this->sqlInsertFlush();
530  }
531  return true;
532  }
533  /**
534  *
535  * @return bool
536  */
537  private function sqlCreateSchema()
538  {
539  try {
540  $this->stdInfo(_("Create Schema '%s' ...") , $this->params['tmpschemaname']);
541  $this->sqlExecute('DROP SCHEMA IF EXISTS "' . $this->params['tmpschemaname'] . '" CASCADE', false);
542  $this->sqlExecute('CREATE SCHEMA "' . $this->params['tmpschemaname'] . '"', false);
543  }
544  catch(Exception $e) {
545  return false;
546  }
547  return true;
548  }
549  /**
550  *
551  * @return bool
552  */
553  private function sqlCreateTables()
554  {
555  try {
556  $this->stdInfo(_("Create Tables ..."));
557  foreach ($this->config as $table) {
558 
559  $insertDefaults = true;
560  $fields = array();
561  switch ($table->type) {
562  case 'enum':
563  case 'enum_multiple':
564  case 'enum_inarray':
565  $fields[] = sprintf(' "%s" %s PRIMARY KEY', 'id', 'text');
566  $fields[] = sprintf(' "%s" %s', 'title', 'text');
567  $table->sqlFields[] = 'id';
568  $table->sqlFields[] = 'title';
569  $insertDefaults = false;
570  break;
571 
572  case 'family':
573  $fields[] = sprintf(' "%s" %s PRIMARY KEY', 'id', 'integer');
574  $fields[] = sprintf(' "%s" %s', 'title', 'text');
575  $table->sqlFields[] = 'id';
576  $table->sqlFields[] = 'title';
577  break;
578 
579  case 'array':
580  $fields[] = sprintf(' "%s" %s PRIMARY KEY', 'id', 'integer');
581  $table->sqlFields[] = 'id';
582  break;
583  }
584  if ($insertDefaults) {
585  foreach ($table->columns as $column) {
586  $fields[] = sprintf(' "%s" %s', $column->name, $column->pgType);
587  $table->sqlFields[] = $column->name;
588  }
589  foreach ($table->properties as $property) {
590  $fields[] = sprintf(' "%s" %s', $property->name, $property->pgType);
591  $table->sqlFields[] = $property->name;
592  }
593  foreach ($table->references as $reference) {
594  $fields[] = sprintf(' "%s" %s', $reference->attributeName, $reference->type);
595  $table->sqlFields[] = $reference->attributeName;
596  }
597  }
598 
599  $this->stdInfo(_("Create Table '%s'") , strtolower($table->name));
600  $this->sqlLogWrite(sprintf("Create table %s", strtolower($table->name)) , true);
601 
602  $sql = sprintf('CREATE TABLE "%s"."%s" (', $this->params['tmpschemaname'], strtolower($table->name)) . "\n";
603  $sql.= implode(",\n", $fields) . "\n)";
604  $this->sqlExecute($sql);
605  }
606  }
607  catch(Exception $e) {
608  return false;
609  }
610  return true;
611  }
612  /**
613  *
614  * @return bool
615  */
616  private function sqlMakeReferences()
617  {
618  try {
619 
620  $this->stdInfo(_("Make references ..."));
621  $this->sqlLogWrite("Building References", true);
622 
623  foreach ($this->config as $table) {
624  foreach ($table->references as $reference) {
625  $sql = sprintf('ALTER TABLE "%s"."%s" ADD CONSTRAINT "%s" FOREIGN KEY ("%s") REFERENCES "%s"."%s" ("%s") MATCH SIMPLE', $this->params['tmpschemaname'], strtolower($table->name) , $reference->attributeName, $reference->attributeName, $this->params['tmpschemaname'], strtolower($reference->foreignTable) , $reference->foreignKey);
626 
627  $this->sqlExecute($sql);
628  }
629  }
630  }
631  catch(Exception $e) {
632  return false;
633  }
634 
635  return true;
636  }
637  /**
638  *
639  * @param string $tableName
640  * @return int
641  */
642  private function sqlNextSequenceId($tableName)
643  {
644  if (isset($this->sqlSequences[$tableName])) {
645  $this->sqlSequences[$tableName]++;
646  return $this->sqlSequences[$tableName];
647  } else {
648  $this->sqlSequences[$tableName] = 1;
649  return 1;
650  }
651  }
652  /**
653  *
654  * @param int $docid
655  */
656  private function sqlGetValidDocId($docid)
657  {
658  $sql = sprintf("SELECT id from docread where initid=(select initid from docread where id=%d) and locked != -1 limit 1;", $docid);
659  $res = @pg_query($this->tmp_conn, $sql);
660  if ($res) {
661  $row = @pg_fetch_row($res);
662  if ($row) {
663  return $row[0];
664  }
665  }
666  return 'NULL';
667  }
668  /**
669  *
670  * @return bool
671  */
672  private function sqlFillTables()
673  {
674  try {
675  $this->stdInfo(_("Fill Tables ..."));
676  // indexes table arrays to improve performance
677  $tablesByName = array();
678  foreach ($this->config as $table) {
679  $tablesByName[strtolower($table->name) ] = $table;
680  }
681  // export family tables
682  foreach ($this->config as $table) {
683  if ($table->type == 'family') {
684  $this->stdInfo(_("Filling family table '%s' and relatives") , strtolower($table->name));
685  $this->sqlLogWrite(sprintf("Filling table %s and relatives", strtolower($table->name)) , true);
686  // search documents
687  $s = new SearchDoc($this->tmp_dbaccess, $table->name);
688  $s->setObjectReturn();
689  //$s->latest = false;
690  //$s->trash = 'also';
691  $s->search();
692  // get field values
693  while ($doc = $s->getNextDoc()) {
694  // document required fields (id, title)
695  $fieldValues = array(
696  $doc->id,
697  $this->getPgEscape($doc->getTitle()) ,
698  );
699  $fieldCopyValues = array(
700  $doc->id,
701  $this->getPgEscapeCopy($doc->getTitle()) ,
702  );
703  // fields
704  foreach ($table->columns as $column) {
705  $fieldValues[] = $column->getPgEscape($doc->getRawValue($column->name));
706  $fieldCopyValues[] = $column->getPgEscapeCopy($doc->getRawValue($column->name));
707  }
708  // properties
709  foreach ($table->properties as $property) {
710  $propertyName = $property->name;
711  $fieldValues[] = $property->getPgEscape($doc->$propertyName);
712  $fieldCopyValues[] = $property->getPgEscapeCopy($doc->$propertyName);
713  }
714  // foreign keys
715  foreach ($table->references as $reference) {
716  $fTable = strtolower($reference->foreignTable);
717  if (!array_key_exists($fTable, $tablesByName)) {
718  $this->stdError(_("Table '%s' unknown !") , $reference->foreignTable);
719  }
720 
721  switch ($tablesByName[$fTable]->type) {
722  case 'family': // docid
723  $value = $doc->getRawValue($reference->attributeName);
724  $id = $this->sqlGetValidDocId($value);
725  $fieldValues[] = $id;
726  $fieldCopyValues[] = $id == 'NULL' ? "\\N" : $id;
727  break;
728 
729  case 'enum':
730  case 'enum_multiple':
731  case 'enum_inarray':
732  $value = $doc->getRawValue($reference->attributeName);
733  $tablesByName[$fTable]->checkEnumValue($value);
734  $fieldValues[] = $this->getPgEscape($value);
735  $fieldCopyValues[] = $this->getPgEscapeCopy($value);
736  break;
737 
738  default:
739  $fieldValues[] = "''";
740  $fieldCopyValues[] = "";
741  break;
742  }
743  }
744 
745  $this->sqlInsert(strtolower($table->name) , $table->sqlFields, $fieldCopyValues, $fieldValues);
746  // manage linked tables :
747  // \_ enum_multiple_link
748  // \_ docid_multiple_link
749  // \_ array
750  // \_ docid_multiple_inarray_link
751  foreach ($table->linkedTables as $type => $linkedTables) {
752  foreach ($linkedTables as $data) {
753  switch ($type) {
754  case 'enum_multiple_link':
755  $values = $doc->getMultipleRawValues($data['column']->name);
756  foreach ($values as $value) {
757  if (isset($data['enumtable'])) {
758  $data['enumtable']->checkEnumValue($value);
759  }
760  $this->sqlInsert(strtolower($data['table']->name) , $data['table']->sqlFields, array(
761  $this->getPgEscapeCopy($value) ,
762  $doc->id
763  ) , array(
764  $this->getPgEscapeCopy($value) ,
765  $doc->id
766  ));
767  }
768  break;
769 
770  case 'docid_multiple_link':
771  $values = $doc->getMultipleRawValues($data['column']->name);
772  foreach ($values as $value) {
773  $id = $this->sqlGetValidDocId($value);
774  $this->sqlInsert(strtolower($data['table']->name) , $data['table']->sqlFields, array(
775  $id == 'NULL' ? "\\N" : $id,
776  $doc->id
777  ) , array(
778  $id,
779  $doc->id
780  ));
781  }
782  break;
783 
784  case 'array':
785  // load all array
786  $array = $doc->getArrayRawValues($data['table']->arrayName);
787  // for each row of array
788  foreach ($array as $iRow => $row) {
789 
790  $arrayId = $this->sqlNextSequenceId($data['table']->name);
791  // init with auto increment id
792  $fieldValues = array();
793  $fieldValues[] = $arrayId;
794  $fieldCopyValues = array();
795  $fieldCopyValues[] = $arrayId;
796  // get values
797  foreach ($data['table']->columns as $col) {
798  $fieldValues[] = $col->getPgEscape($row[$col->name]);
799  $fieldCopyValues[] = $col->getPgEscapeCopy($row[$col->name]);
800  }
801  // foreign keys value
802  foreach ($data['table']->references as $reference) {
803  $fTable = strtolower($reference->foreignTable);
804  if (!array_key_exists($fTable, $tablesByName)) {
805  $this->stdError(_("Table '%s' unknown !") , $reference->foreignTable);
806  }
807  if ($tablesByName[$fTable]->type == 'family' && strtolower($reference->attributeName) == strtolower($reference->foreignTable)) {
808  // link to family
809  $fieldValues[] = $doc->id;
810  $fieldCopyValues[] = $doc->id;
811  continue;
812  }
813  // other attributes
814  $value = $row[$reference->attributeName];
815  if ($tablesByName[$fTable]->type == 'family') { // docid
816  $id = $this->sqlGetValidDocId($value);
817  $fieldValues[] = $id;
818  $fieldCopyValues[] = $id == 'NULL' ? "\\N" : $id;
819  } elseif (in_array($tablesByName[$fTable]->type, array(
820  'enum',
821  'enum_multiple',
822  'enum_inarray'
823  ))) {
824  $tablesByName[$fTable]->checkEnumValue($value);
825  $fieldValues[] = $this->getPgEscape($value);
826  $fieldCopyValues[] = $this->getPgEscapeCopy($value);
827  } else {
828  $fieldValues[] = $this->getPgEscape($value);
829  $fieldCopyValues[] = $this->getPgEscapeCopy($value);
830  }
831  }
832  // insert
833  $this->sqlInsert(strtolower($data['table']->name) , $data['table']->sqlFields, $fieldCopyValues, $fieldValues);
834  // docid multiple in array
835  foreach ($data['linkedTables'] as $data2) {
836  $values = $doc->rawValueToArray(str_replace('<BR>', "\n", $row[$data2['column']->name]));
837  foreach ($values as $val) {
838  $id = $this->sqlGetValidDocId($val);
839  $this->sqlInsert(strtolower($data2['table']->name) , $data2['table']->sqlFields, array(
840  $id == 'NULL' ? "\\N" : $id,
841  $arrayId
842  ) , array(
843  $id,
844  $arrayId
845  ));
846  }
847  }
848  }
849  break;
850  } // end switch
851 
852  }
853  } // end foreach linkedTabled
854 
855  } // end while nextDoc
856 
857  } // end if
858 
859  } // end foreach family
860  // export enum tables
861  foreach ($this->config as $table) {
862  if ($table->type == 'enum' || $table->type == 'enum_multiple' || $table->type == 'enum_inarray') {
863  $this->stdInfo(_("Filling enum table '%s'") , $table->name);
864  $this->sqlLogWrite(sprintf("Filling enum table %s", strtolower($table->name)) , true);
865  foreach ($table->enumDatas as $key => $value) {
866  $this->sqlInsert($table->name, array(
867  'id',
868  'title'
869  ) , array(
870  $this->getPgEscapeCopy($key, false) ,
871  $this->getPgEscapeCopy($value)
872  ) , array(
873  $this->getPgEscape($key, false) ,
874  $this->getPgEscape($value)
875  ));
876  }
877  }
878  }
879  // should flush insert datas before leaving !!
880  $this->sqlInsertFlush();
881  }
882  catch(Exception $e) {
883  return false;
884  }
885  return true;
886  }
887  /**
888  * freedom checks and load
889  * @return bool
890  */
891  private function configLoad()
892  {
893 
894  if (!$this->configLoadFamilies()) return false;
895  if (!$this->configLoadAttributes()) return false;
896  if (!$this->configLoadExplodeContainers()) return false;
897  if (!$this->configLoadTables()) return false;
898  if (!$this->configLoadCheck()) return false;
899 
900  return true;
901  }
902  /**
903  *
904  * @param Form1NF_Table $family
905  * @param string $arrayId
906  * @return array
907  */
908  private function getArrayColumns($family, $arrayName)
909  {
910  $arrayColumns = array();
911  foreach ($family->columns as $i => $column) {
912  if ($column->arrayName == $arrayName) $arrayColumns[$i] = $column;
913  }
914  return $arrayColumns;
915  }
916  /**
917  * freedom checks and load
918  * @return bool
919  */
920  private function configLoadCheck()
921  {
922  try {
923  foreach ($this->config as $iFamily => $family) {
924  // check duplicate columns
925  $delete = array();
926  foreach ($family->columns as $i => $column1) {
927  if (in_array($i, $delete)) continue; // avoid if already deleted
928  foreach ($family->columns as $j => $column2) {
929  if ($i == $j) continue; // avoid check on same column
930  if ($column1->name == $column2->name) {
931  $delete[] = $j;
932  }
933  }
934  }
935  foreach ($delete as $i) {
936  $this->stdInfo(_("Remove duplicate attribute '%s' in family '%s'") , $this->config[$iFamily]->columns[$i]->name, $family->name);
937  unset($this->config[$iFamily]->columns[$i]);
938  }
939  // check duplicate references
940  $delete = array();
941  foreach ($family->references as $i => $ref1) {
942  if (in_array($i, $delete)) continue; // avoid if already deleted
943  foreach ($family->references as $j => $ref2) {
944  if ($i == $j) continue; // avoid check on same column
945  if ($ref1->isSameAs($ref2)) {
946  $delete[] = $j;
947  }
948  }
949  }
950  foreach ($delete as $i) {
951  $this->stdInfo(_("Remove duplicate reference '%s' in family '%s'") , $this->config[$iFamily]->references[$i]->attributeName, $family->name);
952  unset($this->config[$iFamily]->references[$i]);
953  }
954  // the following checks are only for families
955  if ($family->type != 'family') continue;
956  // check duplicate property
957  $delete = array();
958  foreach ($family->properties as $i => $property1) {
959  if (in_array($i, $delete)) continue; // avoid if already deleted
960  foreach ($family->properties as $j => $property2) {
961  if ($i == $j) continue; // avoid check on same column
962  if ($property1->name == $property2->name) {
963  $delete[] = $j;
964  }
965  }
966  }
967  foreach ($delete as $i) {
968  $this->stdInfo(_("Remove duplicate property '%s' in family '%s'") , $this->config[$iFamily]->properties[$i]->name, $family->name);
969  unset($this->config[$iFamily]->properties[$i]);
970  }
971  // check special property
972  $special = array(
973  'id',
974  'title'
975  );
976  $delete = array();
977  foreach ($family->properties as $i => $property) {
978  if (in_array($property->name, $special)) {
979  $delete[] = $i;
980  }
981  }
982  foreach ($delete as $i) {
983  $this->stdInfo(_("Skip already added property '%s' in family '%s'") , $this->config[$iFamily]->properties[$i]->name, $family->name);
984  unset($this->config[$iFamily]->properties[$i]);
985  }
986  }
987  }
988  catch(Exception $e) {
989  return false;
990  }
991  return true;
992  }
993  /**
994  *
995  * @param string $format
996  * @param Form1NF_Table $family
997  */
998  private function getDocidFamily($column, $table)
999  {
1000  if (!empty($column->docidFamily)) return $column->docidFamily;
1001  $found = '';
1002  foreach ($table->famAttributes as $attribute) {
1003  if (!empty($attribute->phpfunc)) {
1004  if (preg_match('/lfamill?y\([a-z]+\s*,\s*([a-z0-9_]+).*\):' . $column->name . '/si', $attribute->phpfunc, $m)) {
1005  $found = $m[1];
1006  break;
1007  }
1008  }
1009  }
1010  // break process if not found
1011  if (empty($found)) {
1012  $this->stdError(_("Attribute Error: impossible to found the family for docid attribute '%s'") , $column->name);
1013  }
1014  // test if family exists
1015  $fam = new_Doc($this->tmp_dbaccess, $found, true);
1016  if (!is_object($fam) || !$fam->isAlive()) {
1017  $this->stdError(_("Attribute Error: family '%s' is not valid or alive for docid '%s'.") , $found, $column->name);
1018  }
1019  return $found;
1020  }
1021  /**
1022  * freedom checks and load
1023  * @return bool
1024  */
1025  private function configLoadTables()
1026  {
1027  try {
1028  foreach ($this->config as $iFamily => $family) {
1029 
1030  if ($family->type != 'family') continue;
1031 
1032  $delete = array();
1033 
1034  foreach ($family->columns as $iColumn => $column) {
1035  if (in_array($iColumn, $delete)) continue;
1036  switch ($column->fullType) {
1037  case 'simple': // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1038  // nothing to do
1039  break;
1040 
1041  case 'enum': // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1042  $tableName = $this->getUniqueTableName($column->name);
1043  $newTable = new Form1NF_Table('enum', $tableName);
1044  $newTable->enumDatas = $column->enumDatas;
1045  $family->references[] = new Form1NF_Reference($tableName, $column->name, 'text');
1046  $this->config[] = $newTable;
1047  $delete[] = $iColumn;
1048  break;
1049 
1050  case 'docid': // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1051  if (empty($column->docidLinkedColumn)) {
1052  // real docid
1053  $table = $this->getConfigTable($this->getDocidFamily($column, $family) , true);
1054  $family->references[] = new Form1NF_Reference($table->name, $column->name);
1055  } else {
1056  // added column
1057  $table = $this->getConfigTable($column->docidLinkedColumn->family, true);
1058  if (!$table->hasColumn($column->docidLinkedColumn->name)) {
1059  $table->columns[] = $column->docidLinkedColumn;
1060  }
1061  }
1062  $table->type = 'family';
1063  $delete[] = $iColumn;
1064  break;
1065 
1066  case 'enum_multiple': // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1067  $tableNameLink = $this->getUniqueTableName($family->name . '_' . $column->name);
1068  $newTableLink = new Form1NF_Table('enum_multiple_link', $tableNameLink);
1069 
1070  $tableNameEnum = $this->getUniqueTableName($column->name);
1071  $newTableEnum = new Form1NF_Table('enum_multiple', $tableNameEnum);
1072  $newTableEnum->enumDatas = $column->enumDatas;
1073 
1074  $newTableLink->references[] = new Form1NF_Reference($tableNameEnum, 'idenum', 'text');
1075  $newTableLink->references[] = new Form1NF_Reference($family->name); // idfamille
1076  $family->linkedTables['enum_multiple_link'][] = array(
1077  'table' => $newTableLink,
1078  'enumtable' => $newTableEnum,
1079  'column' => $column,
1080  );
1081 
1082  $this->config[] = $newTableEnum;
1083  $this->config[] = $newTableLink;
1084 
1085  $delete[] = $iColumn;
1086  break;
1087 
1088  case 'docid_multiple': // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1089  $tableNameLink = $this->getUniqueTableName($family->name . '_' . $column->name);
1090  $newTableLink = new Form1NF_Table('docid_multiple_link', $tableNameLink);
1091 
1092  $newTableDocid = $this->getConfigTable($this->getDocidFamily($column, $family) , true);
1093 
1094  $newTableLink->references[] = new Form1NF_Reference($newTableDocid->name, 'iddoc');
1095  $newTableLink->references[] = new Form1NF_Reference($family->name); // idfamille
1096  $family->linkedTables['docid_multiple_link'][] = array(
1097  'table' => $newTableLink,
1098  'column' => $column,
1099  );
1100 
1101  $this->config[] = $newTableLink;
1102  $newTableDocid->type = 'family';
1103  $delete[] = $iColumn;
1104  break;
1105 
1106  case 'simple_inarray': // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1107 
1108  case 'enum_inarray':
1109  case 'docid_inarray':
1110  case 'docid_multiple_inarray':
1111  // get all columns of array
1112  $arrayColumns = $this->getArrayColumns($family, $column->arrayName);
1113  if ($arrayColumns === false) {
1114  $this->stdError(_("Error: No column found in array '%s'") , $column->arrayName);
1115  }
1116  // get or create table
1117  $tableArrayName = $family->name . '_' . $column->arrayName;
1118  $tableArray = $this->getConfigTable($tableArrayName, true);
1119  $tableArray->type = 'array';
1120  $tableArray->arrayName = $column->arrayName;
1121  $tableArray->references[] = new Form1NF_Reference($family->name); // link to father table
1122  $linkedTable = array(
1123  'table' => $tableArray,
1124  'linkedTables' => array() ,
1125  );
1126  // manage each array field
1127  foreach ($arrayColumns as $i => $col) {
1128  switch ($col->fullType) {
1129  case 'simple_inarray':
1130  if (!$tableArray->hasColumn($col->name)) {
1131  $tableArray->columns[] = $col;
1132  }
1133  break;
1134 
1135  case 'enum_inarray':
1136  $tableEnumName = $this->getUniqueTableName($col->name);
1137  $newTable = new Form1NF_Table('enum_inarray', $tableEnumName);
1138  $newTable->enumDatas = $col->enumDatas;
1139  $tableArray->references[] = new Form1NF_Reference($tableEnumName, $col->name, 'text');
1140  $this->config[] = $newTable;
1141  break;
1142 
1143  case 'docid_inarray':
1144  $tableDocid = $this->getConfigTable($this->getDocidFamily($col, $family) , true);
1145  $tableArray->references[] = new Form1NF_Reference($tableDocid->name, $col->name);
1146  $tableDocid->type = 'family';
1147  break;
1148 
1149  case 'docid_multiple_inarray':
1150  $tableNameLink = $this->getUniqueTableName($tableArrayName . '_' . $col->name);
1151  $newTableLink = new Form1NF_Table('docid_multiple_inarray_link', $tableNameLink);
1152 
1153  $newTableDocid = $this->getConfigTable($this->getDocidFamily($col, $family) , true);
1154 
1155  $newTableLink->references[] = new Form1NF_Reference($newTableDocid->name); // idfamille
1156  $newTableLink->references[] = new Form1NF_Reference($tableArrayName, 'idarray');
1157 
1158  $linkedTable['linkedTables'][] = array(
1159  'table' => $newTableLink,
1160  'column' => $col,
1161  );
1162 
1163  $newTableDocid->type = 'family';
1164  $this->config[] = $newTableLink;
1165  break;
1166 
1167  default:
1168  $this->stdError(_("Incoherent column type '%s' in array '%s'.") , $colType, $column->arrayName);
1169  break;
1170  }
1171  $delete[] = $i;
1172  }
1173  $family->linkedTables['array'][] = $linkedTable;
1174  break;
1175 
1176  default:
1177  $this->stdError(_("Column type '%s' is not managed for export.") , $column->fullType);
1178  break;
1179  }
1180  }
1181  foreach ($delete as $iColumn) unset($this->config[$iFamily]->columns[$iColumn]);
1182  }
1183  }
1184  catch(Exception $e) {
1185  return false;
1186  }
1187  return true;
1188  }
1189  /**
1190  *
1191  * @return bool
1192  */
1193  private function configLoadFamilies()
1194  {
1195  try {
1196  foreach ($this->config as $family) {
1197  // load the family object
1198  $famId = getFamIdFromName($this->tmp_dbaccess, $family->name);
1199  if ($famId === 0) {
1200  // try to lower the name
1201  $famId = getFamIdFromName($this->tmp_dbaccess, strtolower($family->name));
1202  if ($famId === 0) {
1203  // try to upper the name
1204  $famId = getFamIdFromName($this->tmp_dbaccess, strtoupper($family->name));
1205  if ($famId === 0) {
1206  $this->stdError(_("Could not get family id for '%s'.") , $family->name);
1207  }
1208  }
1209  }
1210  // try to load family id
1211  $fam = new_Doc($this->tmp_dbaccess, $famId, true);
1212  if (!is_object($fam) || !$fam->isAlive()) {
1213  $this->stdError(_("Family '%s' is not valid or alive.") , $famId);
1214  }
1215  // load all attributes
1216  $famAttributes = $fam->GetAttributes();
1217  // load attributes
1218  foreach ($famAttributes as $attribute) {
1219  $family->famAttributes[] = new Form1NF_Column($attribute);
1220  }
1221  // checks properties
1222  $allowedProperties = array_keys(Doc::$infofields);
1223  foreach ($family->properties as $property) {
1224  if (!in_array($property->name, $allowedProperties)) {
1225  $this->stdError(_("Property '%s' is not valid (family '%s').") , $property->name, $family->name);
1226  }
1227  // load correct type
1228  $property->setType(Doc::$infofields[$property->name]['type']);
1229  }
1230  }
1231  }
1232  catch(Exception $e) {
1233  return false;
1234  }
1235  return true;
1236  }
1237  /**
1238  *
1239  * @return bool
1240  */
1241  private function configLoadExplodeContainers()
1242  {
1243  try {
1244  foreach ($this->config as $family) {
1245  // explode TABS, ARRAY or FRAMES columns with their attributes
1246  $delete = array();
1247  foreach ($family->columns as $i => $column) {
1248  if (in_array($i, $delete)) continue;
1249  if ($column->isContainer) {
1250  $columns = $family->getChildAttributes($column->name);
1251  if ($columns === false) {
1252  $this->stdError($family->error);
1253  }
1254  foreach ($columns as $col) {
1255  $family->columns[] = $col;
1256  }
1257  $delete[] = $i;
1258  }
1259  }
1260  foreach ($delete as $i) unset($family->columns[$i]);
1261  }
1262  }
1263  catch(Exception $e) {
1264  return false;
1265  }
1266  return true;
1267  }
1268  /**
1269  *
1270  * @return bool
1271  */
1272  private function configLoadAttributes()
1273  {
1274  try {
1275  foreach ($this->config as $family) {
1276  // load each column attribute
1277  foreach ($family->columns as $column) {
1278 
1279  $columnName = $column->name;
1280  $columnLinkedName = '';
1281 
1282  if (strpos($columnName, ':') !== false) {
1283  // <docid:attribute> syntax
1284  list($columnName, $columnLinkedName) = explode(':', $columnName);
1285  }
1286  // search attribute
1287  $attributeFound = null;
1288  foreach ($family->famAttributes as $attribute) {
1289  if ($attribute->name == $columnName) {
1290  $attributeFound = $attribute;
1291  break;
1292  }
1293  }
1294 
1295  if ($attributeFound === null) {
1296  $this->stdError(_("Could not find attribute '%s' in family '%s'.") , $column->name, $family->name);
1297  }
1298 
1299  $column->copyFromColumn($attributeFound);
1300  // search linked docid attribute
1301  if (!empty($columnLinkedName)) {
1302 
1303  if ($attributeFound->type != 'docid') {
1304  $this->stdError(_("Attribute '%s' should reference a docid attribute in family '%s'.") , $column->name, $family->name);
1305  }
1306 
1307  if (empty($attributeFound->docidFamily)) {
1308  $this->stdError(_("Attribute format should not be empty on attribute '%s' in family '%s'.") , $column->name, $family->name);
1309  }
1310 
1311  $doc = new_Doc($this->tmp_dbaccess, $attributeFound->docidFamily);
1312 
1313  if (!is_object($doc) || !$doc->isAlive()) {
1314  $this->stdError(_("Family '%s' is not valid or alive.") , $attributeFound->docidFamily);
1315  }
1316 
1317  $attribute = $doc->getAttribute($columnLinkedName);
1318 
1319  if (!is_object($attribute) || empty($attribute)) {
1320  $this->stdError(_("Attribute '%s' could not be found in family '%s'.") , $columnLinkedName, $attributeFound->docidFamily);
1321  }
1322  $column->docidLinkedColumn = new Form1NF_Column($attribute);
1323  }
1324  }
1325  }
1326  }
1327  catch(Exception $e) {
1328  return false;
1329  }
1330  return true;
1331  }
1332  /**
1333  *
1334  * @param string $name
1335  * @param bool $autocreate
1336  * @return mixed
1337  */
1338  private function getConfigTable($name, $autocreate = false)
1339  {
1340  $return = false;
1341  if (empty($name)) {
1342  $this->stdError(_("Name of table cannot be empty"));
1343  }
1344  foreach ($this->config as $table) {
1345  if (strtolower($table->name) == strtolower($name)) {
1346  $return = $table;
1347  }
1348  }
1349  if (empty($return) && $autocreate) {
1350  $table = new Form1NF_Table('', $name);
1351  $this->config[] = $table;
1352  $return = $table;
1353  }
1354  return $return;
1355  }
1356  /**
1357  *
1358  * @param string $name
1359  */
1360  private function getUniqueTableName($name)
1361  {
1362  $i = 1;
1363  $newName = $name;
1364  while (($found = $this->getConfigTable($newName)) !== false) {
1365  $newName = $name . $i;
1366  $i++;
1367  }
1368  return strtolower($newName);
1369  }
1370  /**
1371  *
1372  * @return string
1373  */
1374  private function checkErrorPostgresql($str = '')
1375  {
1376  if ($this->tmp_conn) {
1377  $err = pg_last_error($this->tmp_conn);
1378  if (!empty($err)) {
1379  $this->stdError('PG Error: ' . $err . (!empty($str) ? "\n" . $str : ''));
1380  }
1381  }
1382  }
1383  /**
1384  *
1385  * @return string
1386  */
1387  private function checkErrorLibXML()
1388  {
1389  $err = libxml_get_last_error();
1390  if (is_object($err)) {
1391  $this->stdError('XML Error: ' . $err->message);
1392  }
1393  return true;
1394  }
1395  /**
1396  * parse XML file : no freedom checks, only xml checks
1397  */
1398  private function configParse()
1399  {
1400 
1401  $msgerr = '';
1402 
1403  try {
1404  // load xml
1405  $xml = new DOMDocument();
1406  $ret = @$xml->load($this->params['config']);
1407  $this->checkErrorLibXML();
1408  // init
1409  $this->config = array();
1410  // search database root
1411  $databaseNodes = @$xml->getElementsByTagName('database');
1412  $this->checkErrorLibXML();
1413  if ($databaseNodes->length == 0) {
1414  $this->stdError(_("XML Error: no <database/> root node."));
1415  }
1416  if ($databaseNodes->length > 1) {
1417  $this->stdError(_("XML Error: only one <database/> root node allowed."));
1418  }
1419  // get database root
1420  $databaseNode = $databaseNodes->item(0);
1421  // table list
1422  $tableNodes = @$databaseNode->getElementsByTagName('table');
1423  $this->checkErrorLibXML();
1424  foreach ($tableNodes as $tableNode) {
1425  // create table
1426  $familyName = $tableNode->getAttribute('family');
1427  if (empty($familyName)) {
1428  $this->stdError(_("XML Error: no 'family' attribute on <table/> node."));
1429  }
1430  $table = new Form1NF_Table('family', $familyName);
1431  // column list
1432  $columnNodes = @$tableNode->getElementsByTagName('column');
1433  $this->checkErrorLibXML();
1434  foreach ($columnNodes as $columnNode) {
1435  // create column
1436  $columnName = strtolower($columnNode->getAttribute('attribute'));
1437  $propertyName = strtolower($columnNode->getAttribute('property'));
1438 
1439  if (empty($columnName) && empty($propertyName)) {
1440  $this->stdError(_("XML Error: no property or attribute on <column/> node."));
1441  }
1442 
1443  if (!empty($columnName)) { // attribute
1444  $table->columns[] = new Form1NF_Column($columnName);
1445  } else { // property
1446  $column = new Form1NF_Column($propertyName);
1447  $column->isProperty = true;
1448  $table->properties[] = $column;
1449  }
1450  }
1451  $this->config[] = $table;
1452  }
1453  if (empty($this->config)) {
1454  $this->stdError(_("XML Error: no table defined."));
1455  }
1456  $this->stdInfo(_("XML config parsed OK !"));
1457  }
1458  catch(Exception $e) {
1459  return false;
1460  }
1461 
1462  return true;
1463  }
1464  /**
1465  * Dump the "Freedom" source database
1466  *
1467  * @return false on error
1468  */
1469  private function databaseDump($pgservice)
1470  {
1471  include_once ('WHAT/Lib.Common.php');
1472 
1473  try {
1474  $this->stdInfo(_("Dump pgservice '%s' ...") , $pgservice);
1475 
1476  $tmp_dump = tempnam(getTmpDir() , 'pg_dump.tmp.1nf.');
1477  if ($tmp_dump === false) {
1478  $this->stdError(_("Error creating temp file for pg_dump output."));
1479  }
1480 
1481  $pg_dump_cmd = LibSystem::getCommandPath('pg_dump');
1482  if ($pg_dump_cmd === false) {
1483  $this->stdError(_("Could not find pg_dump command in PATH."));
1484  }
1485 
1486  $ret = LibSystem::ssystem(array(
1487  $pg_dump_cmd,
1488  '--disable-triggers',
1489  '-f',
1490  $tmp_dump
1491  ) , array(
1492  'closestdin' => true,
1493  'closestdout' => true,
1494  'envs' => array(
1495  'PGSERVICE' => $pgservice,
1496  )
1497  ));
1498 
1499  if ($ret != 0) {
1500  $this->stdError(_("Dump to '%s' returned with exitcode %s") , $tmp_dump, $ret);
1501  }
1502  }
1503  catch(Exception $e) {
1504  return false;
1505  }
1506  return $tmp_dump;
1507  }
1508  /**
1509  * Load the database from the dump
1510  *
1511  * @return false on error
1512  */
1513  private function databaseLoad($dumpFile, $pgservice)
1514  {
1515  try {
1516  $this->stdInfo(_("Load dump file into '%s' ...") , $pgservice);
1517 
1518  $psql_cmd = LibSystem::getCommandPath('psql');
1519  if ($psql_cmd === false) {
1520  $this->stdError(_("Could not find psql command in PATH."));
1521  }
1522 
1523  $ret = LibSystem::ssystem(array(
1524  $psql_cmd,
1525  '--quiet',
1526  '-f',
1527  $dumpFile
1528  ) , array(
1529  'closestdin' => true,
1530  'closestdout' => true,
1531  'envs' => array(
1532  'PGSERVICE' => $pgservice
1533  )
1534  ));
1535  if ($ret != 0) {
1536  $this->stdError(_("Loading of dump '%s' returned with exitcode %s") , $dumpFile, $ret);
1537  }
1538  }
1539  catch(Exception $e) {
1540  return false;
1541  }
1542  return $dumpFile;
1543  }
1544  /**
1545  * Connect to the "Freedom" source database
1546  *
1547  * @return false on error
1548  */
1549  private function freedomDatabaseConnection()
1550  {
1551  try {
1552  $this->conn = @pg_connect($this->freedom_dbaccess);
1553  if ($this->conn === false) {
1554  $this->stdError(_("PG Error: Connection to freedom pg service '%s' failed !") , $this->freedom_pgservice);
1555  }
1556  }
1557  catch(Exception $e) {
1558  return false;
1559  }
1560  $this->stdInfo(_("Connection to freedom pg service '%s' OK !") , $this->freedom_pgservice);
1561  return $this->conn;
1562  }
1563  /**
1564  * Connect to the "Freedom" source database
1565  *
1566  * @return false on error
1567  */
1568  private function tmpDatabaseConnection()
1569  {
1570  try {
1571  $this->tmp_conn = @pg_connect($this->tmp_dbaccess);
1572  if ($this->tmp_conn === false) {
1573  $this->stdError(_("PG Error: Connection to temporary pg service '%s' failed !") , $this->params['tmppgservice']);
1574  }
1575  }
1576  catch(Exception $e) {
1577  return false;
1578  }
1579  $this->stdInfo(_("Connection to temporary pg service '%s' OK !") , $this->params['tmppgservice']);
1580  return $this->tmp_conn;
1581  }
1582  /**
1583  *
1584  * @return bool
1585  */
1586  private function tmpDatabaseEmpty()
1587  {
1588  try {
1589  $this->stdInfo(_("Emptying temporary database '%s' ...") , $this->params['tmppgservice']);
1590  foreach ($this->dropSchemas as $schema) {
1591  $this->sqlExecute(sprintf('DROP SCHEMA IF EXISTS "%s" CASCADE', $schema) , false);
1592  }
1593  $this->sqlExecute('CREATE SCHEMA "public"', false);
1594  }
1595  catch(Exception $e) {
1596  return false;
1597  }
1598  return true;
1599  }
1600 }
1601 /**
1602  *
1603  */
1605 {
1606  /**
1607  *
1608  * @var string
1609  */
1610  public $foreignTable = '';
1611  /**
1612  *
1613  * @var string
1614  */
1615  public $foreignKey = '';
1616  /**
1617  *
1618  * @var string
1619  */
1620  public $attributeName = '';
1621  /**
1622  *
1623  * @var string
1624  */
1625  public $type = '';
1626  /**
1627  *
1628  */
1629  public function __construct($foreignTable, $attributeName = '', $type = 'integer', $foreignKey = 'id')
1630  {
1631  $this->foreignKey = $foreignKey;
1632  $this->foreignTable = $foreignTable;
1633  $this->attributeName = empty($attributeName) ? strtolower($foreignTable) : strtolower($attributeName);
1634  $this->type = $type;
1635  }
1636  /**
1637  *
1638  * @param Form1NF_Reference $ref
1639  */
1640  public function isSameAs($ref)
1641  {
1642  if ($this->attributeName != $ref->attributeName) return false;
1643  if ($this->foreignTable != $ref->foreignTable) return false;
1644  if ($this->foreignKey != $ref->foreignKey) return false;
1645  if ($this->type != $ref->type) return false;
1646  return true;
1647  }
1648 }
1649 /**
1650  *
1651  */
1653 {
1654  /**
1655  *
1656  * @var string
1657  */
1658  public $error = '';
1659  /**
1660  *
1661  * @var string
1662  */
1663  public $type = 'family'; // family, array, enum, enum_multiple, docid, docid_multiple
1664 
1665  /**
1666  *
1667  * @var string
1668  */
1669  public $arrayName = '';
1670  /**
1671  *
1672  * @var string
1673  */
1674  public $name = '';
1675  /**
1676  *
1677  * @var array
1678  */
1679  public $famAttributes = array();
1680  /**
1681  *
1682  * @var array
1683  */
1684  public $sqlFields = array();
1685  /**
1686  * only for enums
1687  * @var array
1688  */
1689  public $enumDatas = array();
1690  /**
1691  *
1692  * @var array[int]Form1NF_Column
1693  */
1694  public $columns = array();
1695  /**
1696  *
1697  * @var array[int]Form1NF_Column
1698  */
1699  public $properties = array();
1700  /**
1701  *
1702  * @var array[int]Form1NF_Reference
1703  */
1704  public $references = array();
1705  /**
1706  *
1707  * @var array
1708  */
1709  public $linkedTables = array();
1710  /**
1711  *
1712  * @param string $type
1713  * @param string $name
1714  */
1715  public function __construct($type, $name)
1716  {
1717  $this->type = $type;
1718  $this->name = $name;
1719  }
1720  /**
1721  * this is usefull for enum free : add dynamically key/value pairs during
1722  * family table filling
1723  * @param string $value
1724  */
1725  public function checkEnumValue($value)
1726  {
1727  if ("$value" === "") return false;
1728  if (!array_key_exists($value, $this->enumDatas)) {
1729  $this->enumDatas[$value] = $value;
1730  }
1731  }
1732  /**
1733  *
1734  * @param string $name
1735  * @return array
1736  */
1737  public function getChildAttributes($name)
1738  {
1739 
1740  $columns = array();
1741  foreach ($this->famAttributes as $attribute) {
1742  if ($attribute->type == 'array') continue;
1743  if ($attribute->type == 'frame') continue;
1744  if ($attribute->type == 'tab') continue;
1745  if (in_array($name, $attribute->containers)) {
1746  $columns[] = $attribute;
1747  }
1748  }
1749 
1750  return $columns;
1751  }
1752  /**
1753  *
1754  * @param string $name
1755  * @return bool
1756  */
1757  public function hasColumn($name)
1758  {
1759  foreach ($this->columns as $column) {
1760  if (strtolower($column->name) == strtolower($name)) return $column;
1761  }
1762  return false;
1763  }
1764 }
1765 /**
1766  *
1767  */
1769 {
1770  /**
1771  *
1772  * @var string
1773  */
1774  public $name = null;
1775  /**
1776  *
1777  * @var string
1778  */
1779  public $type = null;
1780  /**
1781  *
1782  * @var string
1783  */
1784  public $fullType = null;
1785  /**
1786  *
1787  * @var string
1788  */
1789  public $pgType = null;
1790  /**
1791  *
1792  * @var string
1793  */
1794  public $docidLinkedColumn = null;
1795  /**
1796  *
1797  * @var string
1798  */
1799  public $docidFamily = '';
1800  /**
1801  *
1802  * @var string
1803  */
1804  public $arrayName = '';
1805  /**
1806  *
1807  * @var string
1808  */
1809  public $family = '';
1810  /**
1811  *
1812  * @var string
1813  */
1814  public $phpfunc = '';
1815  /**
1816  *
1817  * @var bool
1818  */
1819  public $isMultiple = false;
1820  /**
1821  *
1822  * @var bool
1823  */
1824  public $isProperty = false;
1825  /**
1826  *
1827  * @var bool
1828  */
1829  public $isEnum = false;
1830  /**
1831  *
1832  * @var bool
1833  */
1834  public $isDocid = false;
1835  /**
1836  *
1837  * @var bool
1838  */
1839  public $isContainer = false;
1840  /**
1841  *
1842  * @var bool
1843  */
1844  public $inArray = false;
1845  /**
1846  *
1847  * @var array
1848  */
1849  public $containers = array();
1850  /**
1851  *
1852  * @var array
1853  */
1854  public $enumDatas = array();
1855  /**
1856  *
1857  * @param Form1NF_Table $parent
1858  * @param string $name
1859  * @param object $attribute
1860  */
1861  public function __construct($name = null, $type = null)
1862  {
1863  if (is_object($name)) {
1864  $this->loadFromAttribute($name);
1865  } else {
1866  if ($name !== null) $this->name = strtolower($name);
1867  if ($type !== null) $this->type = $type;
1868  }
1869  }
1870  /**
1871  *
1872  * @param object $attribute
1873  */
1874  public function loadFromAttribute($attribute)
1875  {
1876  $this->name = $attribute->id;
1877  $this->type = $attribute->type;
1878  $this->family = $attribute->docname;
1879  $this->phpfunc = $attribute->phpfunc;
1880  $this->docidFamily = $attribute->format;
1881  $this->isMultiple = ($attribute->getOption('multiple') == 'yes');
1882  $this->inArray = ($attribute->inArray());
1883 
1884  if ($this->type == 'thesaurus') {
1885  $this->type = 'docid';
1886  $this->docidFamily = 'THCONCEPT';
1887  }
1888 
1889  $this->isEnum = ($this->type == 'enum');
1890  $this->isDocid = ($this->type == 'docid');
1891  $this->isContainer = ($this->type == 'tab' || $this->type == 'frame' || $this->type == 'array');
1892 
1893  if ($this->isEnum) $this->enumDatas = $attribute->getEnum();
1894 
1895  $this->pgType = $this->getPgType();
1896  $this->fullType = $this->getFullType();
1897  $this->loadContainers($attribute->fieldSet);
1898  }
1899  /**
1900  *
1901  * @param string $type
1902  */
1903  public function setType($type)
1904  {
1905  $this->type = $type;
1906  $this->pgType = $this->getPgType();
1907  $this->fullType = $this->getFullType();
1908  }
1909  /**
1910  *
1911  * @param object $attribute
1912  */
1913  public function copyFromColumn($column)
1914  {
1915  foreach ($this as $ppt => $value) {
1916  $this->$ppt = $column->$ppt;
1917  }
1918  }
1919  /**
1920  *
1921  * @param object $fieldset
1922  */
1923  private function loadContainers($fieldset)
1924  {
1925  if (!is_object($fieldset)) return;
1926  if ($fieldset->id == \Adoc::HIDDENFIELD) return;
1927  if (empty($this->arrayName) && $fieldset->type == 'array') $this->arrayName = $fieldset->id;
1928  $this->containers[] = $fieldset->id;
1929  if (property_exists($fieldset, 'fieldSet')) {
1930  $this->loadContainers($fieldset->fieldSet);
1931  }
1932  }
1933  /**
1934  *
1935  * @param mixed $value
1936  * @return string;
1937  */
1938  public function getPgEscape($value, $pgType = null)
1939  {
1940  if ($pgType === null) {
1941  $pgType = $this->getPgType();
1942  }
1943  if ("$value" === "") return 'NULL';
1944  if ($pgType == 'integer' || $pgType == 'double precision') return $value;
1945  if ($this->isProperty && $this->name == 'revdate') $value = date('Y-m-d H:i:s', $value);
1946  return "'" . pg_escape_string($value) . "'";
1947  }
1948  /**
1949  *
1950  * @param mixed $value
1951  * @return string;
1952  */
1953  public function getPgEscapeCopy($value, $pgType = null)
1954  {
1955  if ("$value" === "") return "\\N";
1956  if ($this->isProperty && $this->name == 'revdate') $value = date('Y-m-d H:i:s', $value);
1957  $value = pg_escape_string($value);
1958  $value = str_replace(array(
1959  "\r",
1960  "\n",
1961  "\t"
1962  ) , array(
1963  "\\r",
1964  "\\n",
1965  "\\t"
1966  ) , $value);
1967  return $value;
1968  }
1969  /**
1970  *
1971  * @param string $freedom_type
1972  * @return string
1973  */
1974  private function getPgType($freedom_type = null)
1975  {
1976  if ($freedom_type === null) {
1977  $freedom_type = $this->type;
1978  }
1979  switch ($freedom_type) {
1980  case 'date':
1981  return 'date';
1982  case 'time':
1983  return 'time without time zone';
1984  case 'timestamp':
1985  return 'timestamp without time zone';
1986  case 'integer':
1987  case 'docid':
1988  case 'thesaurus':
1989  case 'uid':
1990  case 'int':
1991  return 'integer';
1992  case 'double':
1993  case 'money':
1994  return 'double precision';
1995  case 'tab':
1996  case 'frame':
1997  case 'array':
1998  return false;
1999  case 'enum':
2000  case 'text':
2001  case 'longtext':
2002  case 'htmltext':
2003  case 'password':
2004  case 'file':
2005  case 'image':
2006  case 'color':
2007  case 'ifile':
2008  default:
2009  return 'text';
2010  }
2011  }
2012  /**
2013  *
2014  * @return string
2015  */
2016  private function getFullType()
2017  {
2018  $type = 'simple';
2019  if ($this->isEnum) $type = 'enum';
2020  elseif ($this->isDocid) $type = 'docid';
2021 
2022  if ($this->isMultiple) $type.= '_multiple';
2023  if ($this->inArray) $type.= '_inarray';
2024 
2025  return $type;
2026  }
2027 }
static $infofields
Definition: Class.Doc.php:105
static ssystem($args, $opt=null)
Definition: Lib.System.php:69
if(substr($wsh, 0, 1)!= '/') $args
$s type
Definition: dav.php:73
$comment
Definition: fdl_execute.php:35
if($_POST["login"]=="")
Definition: chgpasswd.php:19
print $fam getTitle() $fam name
Exception class use exceptionCode to identifiy correctly exception.
Definition: exceptions.php:19
$attribute
$ret
__construct($type, $name)
__construct($params)
if($famId) $s
print docid
Definition: migrEnum.php:33
checkEnumValue($value)
$log
Definition: wsh.php:33
static getCommandPath($cmdname)
Definition: Lib.System.php:23
$docid
Definition: cleanFamily.php:13
__construct($foreignTable, $attributeName= '', $type= 'integer', $foreignKey= 'id')
$rows
Definition: Api/ods2csv.php:23
getServiceFreedom()
Definition: Lib.Common.php:446
getFamIdFromName($dbaccess, $name)
getTmpDir($def= '/tmp')
Definition: Lib.Common.php:150
new_Doc($dbaccess, $id= '', $latest=false)
getPgEscape($value, $pgType=null)
loadFromAttribute($attribute)
getPgEscapeCopy($value, $pgType=null)
__construct($name=null, $type=null)
getChildAttributes($name)
copyFromColumn($column)
if($file) if($subject==""&&$file) if($subject=="") $err
$value
$data
← centre documentaire © anakeen