Platform  3.1
PHP API documentation
 All Data Structures Namespaces Files Functions Variables Pages
Class.Doc.php
Go to the documentation of this file.
1 <?php
2 /*
3  * @author Anakeen
4  * @license http://creativecommons.org/licenses/by-nc-sa/2.0/fr/ Anakeen - licence CC
5  * @package FDL
6 */
7 /**
8  * Document Object Definition
9  *
10  * @author Anakeen 2002
11  * @version $Id: Class.Doc.php,v 1.562 2009/01/14 09:18:05 eric Exp $
12  * @license http://creativecommons.org/licenses/by-nc-sa/2.0/fr/ Anakeen - licence CC
13  * @package FDL
14  */
15 /**
16  */
17 
18 include_once ("Class.QueryDb.php");
19 include_once ("Lib.FileMime.php");
20 include_once ("FDL/Class.DocCtrl.php");
21 include_once ("FDL/freedom_util.php");
22 include_once ("FDL/Class.DocVaultIndex.php");
23 include_once ("FDL/Class.DocAttr.php");
24 include_once ("FDL/Class.DocHisto.php");
25 include_once ('FDL/Class.ADoc.php');
26 // define constant for search attributes in concordance with the file "init.freedom"
27 /**#@+
28  * constant for document family identificator in concordance with the file "FDL/init.freedom"
29  *
30 */
31 define("FAM_BASE", 1);
32 define("FAM_DIR", 2);
33 define("FAM_ACCESSDOC", 3);
34 define("FAM_ACCESSDIR", 4);
35 define("FAM_SEARCH", 5);
36 define("FAM_ACCESSSEARCH", 6);
37 define("FAM_ACCESSFAM", 23);
38 define("MENU_ACTIVE", 1);
39 define("MENU_INVISIBLE", 2);
40 define("MENU_INACTIVE", 0);
41 
42 define('POPUP_INACTIVE', 0);
43 define('POPUP_ACTIVE', 1);
44 define('POPUP_CTRLACTIVE', 3);
45 define('POPUP_CTRLINACTIVE', 4);
46 define('POPUP_INVISIBLE', 2);
47 
48 define("DELVALUE", 'DEL??');
49 /**#@-*/
50 /**
51  * max cache document
52  */
53 define("MAXGDOCS", 20);
54 
55 define("REGEXPFILE", "([^\|]*)\|([0-9]*)\|?(.*)?");
56 define("PREGEXPFILE", "/([^\|]*)\|([0-9]*)\|?(.*)?/");
57 /**
58  * Document Class
59  *
60  */
61 class Doc extends DocCtrl
62 {
63  public $fields = array(
64  "id",
65  "owner",
66  "title",
67  "revision",
68  "version",
69  "initid",
70  "fromid",
71  "doctype",
72  "locked",
73  "allocated",
74  "archiveid",
75  "icon",
76  "lmodify",
77  "profid",
78  "usefor",
79  "cdate",
80  "adate",
81  "revdate",
82  "comment",
83  "classname",
84  "state",
85  "wid",
86  "postitid",
87  "forumid",
88  "domainid",
89  "lockdomainid",
90  "cvid",
91  "name",
92  "dprofid",
93  "atags",
94  "prelid",
95  "confidential",
96  "ldapdn"
97  );
98 
99  public $sup_fields = array(
100  "values",
101  "attrids"
102  ); // not be in fields else trigger error
103  public $infofields = array(
104  "id" => array(
105  "type" => "integer",
106  "displayable" => true,
107  "sortable" => true,
108  "filterable" => true,
109  "label" => "prop_id"
110  ) , # N_("prop_id")
111  "owner" => array(
112  "type" => "uid",
113  "displayable" => true,
114  "sortable" => true,
115  "filterable" => true,
116  "label" => "prop_owner"
117  ) , # N_("prop_owner"),
118  "icon" => array(
119  "type" => "image",
120  "displayable" => true,
121  "sortable" => false,
122  "filterable" => false,
123  "label" => "prop_icon"
124  ) , # N_("prop_icon"),
125  "title" => array(
126  "type" => "text",
127  "displayable" => true,
128  "sortable" => true,
129  "filterable" => true,
130  "label" => "prop_title"
131  ) , # N_("prop_title"),
132  "revision" => array(
133  "type" => "integer",
134  "displayable" => true,
135  "sortable" => true,
136  "filterable" => true,
137  "label" => "prop_revision"
138  ) , # N_("prop_revision"),
139  "version" => array(
140  "type" => "text",
141  "displayable" => true,
142  "sortable" => true,
143  "filterable" => true,
144  "label" => "prop_version"
145  ) , # N_("prop_version"),
146  "initid" => array(
147  "type" => "docid",
148  "displayable" => true,
149  "sortable" => true,
150  "filterable" => true,
151  "label" => "prop_initid"
152  ) , # N_("prop_initid"),
153  "fromid" => array(
154  "type" => "docid",
155  "displayable" => true,
156  "sortable" => true,
157  "filterable" => true,
158  "label" => "prop_fromid"
159  ) , # N_("prop_fromid"),
160  "doctype" => array(
161  "type" => "text",
162  "displayable" => false,
163  "sortable" => true,
164  "filterable" => true,
165  "label" => "prop_doctype"
166  ) , # N_("prop_doctype"),
167  "locked" => array(
168  "type" => "uid",
169  "displayable" => true,
170  "sortable" => false,
171  "filterable" => false,
172  "label" => "prop_locked"
173  ) , # N_("prop_locked"),
174  "allocated" => array(
175  "type" => "uid",
176  "displayable" => false,
177  "sortable" => true,
178  "filterable" => true,
179  "label" => "prop_allocated"
180  ) , # N_("prop_allocated"),
181  "lmodify" => array(
182  "type" => "text",
183  "displayable" => false,
184  "sortable" => false,
185  "filterable" => false,
186  "label" => "prop_lmodify"
187  ) , # N_("prop_lmodify"),
188  "profid" => array(
189  "type" => "integer",
190  "displayable" => false,
191  "sortable" => false,
192  "filterable" => false,
193  "label" => "prop_profid"
194  ) , # N_("prop_profid"),
195  "usefor" => array(
196  "type" => "text",
197  "displayable" => false,
198  "sortable" => false,
199  "filterable" => false,
200  "label" => "prop_usefor"
201  ) , # N_("prop_usefor")
202  "cdate" => array(
203  "type" => "timestamp",
204  "displayable" => true,
205  "sortable" => true,
206  "filterable" => true,
207  "label" => "prop_cdate"
208  ) , # N_("prop_cdate")
209  "adate" => array(
210  "type" => "timestamp",
211  "displayable" => true,
212  "sortable" => true,
213  "filterable" => true,
214  "label" => "prop_adate"
215  ) , # N_("prop_adate"),
216  "revdate" => array(
217  "type" => "timestamp",
218  "displayable" => true,
219  "sortable" => true,
220  "filterable" => true,
221  "label" => "prop_revdate"
222  ) , # N_("prop_revdate"),
223  "comment" => array(
224  "type" => "text",
225  "displayable" => false,
226  "sortable" => false,
227  "filterable" => false,
228  "label" => "prop_comment"
229  ) , # N_("prop_comment"),
230  "classname" => array(
231  "type" => "text",
232  "displayable" => false,
233  "sortable" => false,
234  "filterable" => false,
235  "label" => "prop_classname"
236  ) , # N_("prop_classname")
237  "state" => array(
238  "type" => "text",
239  "displayable" => true,
240  "sortable" => true,
241  "filterable" => true,
242  "label" => "prop_state"
243  ) , # N_("prop_state"),
244  "wid" => array(
245  "type" => "docid",
246  "displayable" => false,
247  "sortable" => false,
248  "filterable" => false,
249  "label" => "prop_wid"
250  ) , # N_("prop_wid")
251  "postitid" => array(
252  "type" => "text",
253  "displayable" => false,
254  "sortable" => false,
255  "filterable" => false,
256  "label" => "prop_postitid"
257  ) , # N_("prop_postitid")
258  "forumid" => array(
259  "type" => "docid",
260  "displayable" => false,
261  "sortable" => false,
262  "filterable" => false,
263  "label" => "forum_id"
264  ) , # N_("forum_id")
265  "cvid" => array(
266  "type" => "integer",
267  "displayable" => false,
268  "sortable" => false,
269  "filterable" => false,
270  "label" => "prop_cvid"
271  ) , # N_("prop_cvid")
272  "name" => array(
273  "type" => "text",
274  "displayable" => true,
275  "sortable" => true,
276  "filterable" => true,
277  "label" => "prop_name"
278  ) , # N_("prop_name")
279  "dprofid" => array(
280  "type" => "docid",
281  "displayable" => false,
282  "sortable" => false,
283  "filterable" => false,
284  "label" => "prop_dprofid"
285  ) , # N_("prop_dprofid")
286  "atags" => array(
287  "type" => "text",
288  "displayable" => false,
289  "sortable" => false,
290  "filterable" => false,
291  "label" => "prop_atags"
292  ) , # N_("prop_atags")
293  "prelid" => array(
294  "type" => "docid",
295  "displayable" => false,
296  "sortable" => false,
297  "filterable" => false,
298  "label" => "prop_prelid"
299  ) , # N_("prop_prelid")
300  "lockdomainid" => array(
301  "type" => "docid",
302  "displayable" => true,
303  "sortable" => true,
304  "filterable" => false,
305  "label" => "prop_lockdomainid"
306  ) , # N_("prop_lockdomainid")
307  "domainid" => array(
308  "type" => "docid",
309  "displayable" => false,
310  "sortable" => false,
311  "filterable" => false,
312  "label" => "prop_domainid"
313  ) , # N_("prop_domainid")
314  "confidential" => array(
315  "type" => "integer",
316  "displayable" => false,
317  "sortable" => false,
318  "filterable" => true,
319  "label" => "prop_confidential"
320  ) , # N_("prop_confidential")
321  "svalues" => array(
322  "type" => "fulltext",
323  "displayable" => false,
324  "sortable" => false,
325  "filterable" => true,
326  "label" => "prop_svalues"
327  ) , # N_("prop_svalues")
328  "ldapdn" => array(
329  "type" => "text",
330  "displayable" => false,
331  "sortable" => false,
332  "filterable" => false,
333  "label" => "prop_ldapdn"
334  )
335  ); # N_("prop_ldapdn");
336 
337  /**
338  * identificator of the document
339  * @public int
340  */
341  public $id;
342  /**
343  * user identificator for the creator
344  * @public int
345  */
346  public $owner;
347  /**
348  * the title of the document
349  * @public string
350  */
351  public $title;
352  /**
353  * number of the revision. First is zero
354  * @public int
355  */
356  public $revision;
357  /**
358  * tag for version
359  * @public string
360  */
361  public $version;
362  /**
363  * identificator of the first revision document
364  * @public int
365  */
366  public $initid;
367  /**
368  * identificator of the family document
369  * @public int
370  */
371  public $fromid;
372  /**
373  * domain where document is lock
374  * @public int
375  */
377  /**
378  * domain where document is attached
379  * @public array
380  */
381  public $domainid;
382  /**
383  * the type of document
384  *
385  * F : normal document (default)
386  * C : family document
387  * D : folder document
388  * P : profil document
389  * S : search document
390  * T : temporary document
391  * W : workflow document
392  * Z : zombie document
393  *
394  * @public char
395  */
396  public $doctype;
397  /**
398  * user identificator for the locker
399  * @public int
400  */
401  public $locked;
402  /**
403  * filename or vault id for the icon
404  * @public string
405  */
406  public $icon;
407  /**
408  * set to 'Y' if the document has been modify until last revision
409  * @public char
410  */
411  public $lmodify;
412  /**
413  * identificator of the profil document
414  * @public int
415  */
416  public $profid;
417  /**
418  * to precise a special use of the document
419  * @public char
420  */
421  public $usefor;
422  /**
423  * date of the last modification (the revision date for fixed document)
424  * @public int
425  */
426  public $revdate;
427  /**
428  * date of creation
429  * @public date
430  */
431  public $cdate;
432  /**
433  * date of latest access
434  * @public date
435  */
436  public $adate;
437  /**
438  * date of the last modification (the revision date for fixed docuemnt)
439  * @public int
440  */
441  public $comment;
442  /**
443  * class name in case of special family (only set in family document)
444  * @public string
445  */
446  public $classname;
447  /**
448  * state of the document if it is associated with a workflow
449  * @public string
450  */
451  public $state;
452  /**
453  * identificator of the workflow document
454  *
455  * if 0 then no workflow
456  * @public int
457  */
458  public $wid;
459  /**
460  * identificator of the control view document
461  *
462  * if 0 then no special control view
463  * @public int
464  */
465  public $cvid;
466  /**
467  * string identificator of the document
468  *
469  * @public string
470  */
471  public $name;
472  /**
473  * identificator of the mask document
474  *
475  * if 0 then no mask
476  * @public int
477  */
478  public $mid = 0;
479  /**
480  * identificator of dynamic profil
481  *
482  * if 0 then no dynamic profil
483  * @public int
484  */
485  public $dprofid = 0;
486  /**
487  * primary relation id
488  *
489  * generally towards a folder
490  * @public int
491  */
492  public $prelid = 0;
493  /**
494  * applications tag
495  * use by specifics applications to search documents by these tags
496  *
497  * @public string
498  */
499  public $atag;
500  /**
501  * confidential level
502  * if not 0 this document is confidential, only user with the permission 'confidential' can read this
503  *
504  * @public int
505  */
507  /**
508  * Distinguish Name for LDAP use
509  *
510  * @public text
511  */
512  public $ldapdn;
513  /**
514  * Allocate user id
515  *
516  * @public int
517  */
518  public $allocated;
519  /**
520  * Archive document id
521  *
522  * @public int
523  */
524  public $archiveid;
525  /**
526  * identification of special views
527  *
528  * @public array
529  */
530  public $cviews = array(
531  "FDL:VIEWBODYCARD",
532  "FDL:VIEWABSTRACTCARD",
533  "FDL:VIEWTHUMBCARD"
534  );
535  public $eviews = array(
536  "FDL:EDITBODYCARD"
537  );
538 
539  public static $sqlindex = array(
540  "doc_initid" => array(
541  "unique" => false,
542  "on" => "initid"
543  ) ,
544  "doc_title" => array(
545  "unique" => false,
546  "on" => "title"
547  ) ,
548  "doc_name" => array(
549  "unique" => true,
550  "on" => "name,revision,doctype"
551  ) ,
552  "doc_full" => array(
553  "unique" => false,
554  "using" => "@FDL_FULLIDX",
555  "on" => "fulltext"
556  ) ,
557  "doc_profid" => array(
558  "unique" => false,
559  "on" => "profid"
560  )
561  );
562  public $id_fields = array(
563  "id"
564  );
565 
566  public $dbtable = "doc";
567 
568  public $order_by = "title, revision desc";
569 
570  public $fulltextfields = array(
571  "title"
572  );
573  private $mvalues = array();
574  /**
575  * number of disabledEditControl
576  */
577  private $withoutControlN = 0;
578  private $withoutControl = false;
579  private $constraintbroken = false; // true if one constraint is not verified
580 
581  /**
582  * default family id for the profil access
583  * @public int
584  */
586  public $sqlcreate = "
587 create table doc ( id int not null,
588  primary key (id),
589  owner int,
590  title varchar(256),
591  revision int DEFAULT 0,
592  initid int,
593  fromid int,
594  doctype char DEFAULT 'F',
595  locked int DEFAULT 0,
596  archiveid int DEFAULT 0,
597  allocated int DEFAULT 0,
598  icon varchar(256),
599  lmodify char DEFAULT 'N',
600  profid int DEFAULT 0,
601  usefor char DEFAULT 'N',
602  revdate int,
603  version text,
604  cdate timestamp,
605  adate timestamp,
606  comment text,
607  classname varchar(64),
608  state varchar(64),
609  wid int DEFAULT 0,
610  values text DEFAULT '',
611  attrids text DEFAULT '',
612  fulltext tsvector,
613  postitid text,
614  forumid int,
615  domainid text,
616  lockdomainid int,
617  cvid int,
618  name text,
619  dprofid int DEFAULT 0,
620  prelid int DEFAULT 0,
621  atags text,
622  confidential int DEFAULT 0,
623  ldapdn text,
624  svalues text DEFAULT ''
625  );
626 create table docfrom ( id int not null,
627  primary key (id),
628  fromid int);
629 create table docname ( name text not null,
630  primary key (name),
631  id int,
632  fromid int);
633 create sequence seq_id_doc start 1000;
634 create sequence seq_id_tdoc start 1000000000;
635 create index i_docname on doc(name);
636 create unique index i_docir on doc(initid, revision);";
637  // --------------------------------------------------------------------
638  //---------------------- OBJECT CONTROL PERMISSION --------------------
639  public $obj_acl = array(); // set by childs classes
640  // --------------------------------------------------------------------
641 
642  /**
643  * default view to view card
644  * @public string
645  */
646  public $defaultview = "FDL:VIEWBODYCARD";
647  /**
648  * default view to edit card
649  * @public string
650  */
651  public $defaultedit = "FDL:EDITBODYCARD";
652  /**
653  * default view for abstract card
654  * @public string
655  */
656  public $defaultabstract = "FDL:VIEWABSTRACTCARD";
657  /**
658  * for email : the same as $defaultview by default
659  * @public string
660  */
661  public $defaultmview = "";
662  /**
663  * use when family wants to define a special context menu
664  * @public array
665  */
666  public $specialmenu = array();
667 
668  public $defDoctype = 'F';
669  /**
670  * to indicate values modification
671  * @public bool
672  * @access private
673  */
674  private $hasChanged = false;
675 
676  public $isCacheble = false;
677 
678  public $paramRefresh = array();
679  /**
680  * optimize: compute mask in needed only
681  * @public bool
682  * @access private
683  */
684  private $_maskApplied = false; // optimize: compute mask if needed only
685 
686 
687  /**
688  * Increment sequence of family and call to {@see PostCreated()}
689  *
690  *
691  * @return void
692  */
693  final public function PostInsert()
694  {
695  // controlled will be set explicitly
696  //$this->SetControl();
697  if (($this->revision == 0) && ($this->doctype != "T")) {
698  // increment family sequence
699  $this->nextSequence();
700  $this->Addcomment(_("document creation") , HISTO_INFO, "CREATE");
701  if ($this->wdoc) {
702  $this->wdoc->workflowSendMailTemplate($this->state, _("creation"));
703  $this->wdoc->workflowAttachTimer($this->state);
704  $this->wdoc->changeAllocateUser($this->state);
705  }
706  $this->addLog("create", array(
707  "id" => $this->id,
708  "title" => $this->title,
709  "fromid" => $this->fromid,
710  "fromname" => $this->fromname
711  ));
712  }
713  $this->Select($this->id);
714  // set creation date
715  $this->cdate = $this->getTimeDate(0, true);
716  $this->adate = $this->cdate;
717  $date = gettimeofday();
718  $this->revdate = $date['sec'];
719  $this->modify(true, array(
720  "cdate",
721  "adate",
722  "revdate"
723  ) , true); // to force also execute sql trigger
724  if ($this->doctype != "T") {
725  $err = $this->PostCreated();
726  if ($err != "") AddWarningMsg($err);
727  $this->sendTextToEngine();
728  if ($this->dprofid > 0) {
729  $this->setProfil($this->dprofid); // recompute profil if needed
730  $this->modify(true, array(
731  "profid"
732  ) , true);
733  }
734  $this->UpdateVaultIndex();
735  $this->updateRelations(true);
736  }
737  $this->hasChanged = false;
738 
739  global $gdocs; // set to cache
740  if (count($gdocs) < MAXGDOCS && ($this->doctype != 'C')) {
741  $gdocs[$this->id] = & $this;
742  }
743  }
744 
745  function setChanged()
746  {
747  $this->hasChanged = true;
748  }
749  function isChanged()
750  {
751  return ($this->hasChanged === true);
752  }
753  /**
754  * set default values and creation date
755  * the access control is provided by {@see createDoc()} function.
756  * call {@see Doc::PreCreated()} method before execution
757  *
758  * @return string error message, if no error empty string
759  */
760  final public function PreInsert()
761  {
762 
763  $err = $this->PreCreated();
764  if ($err != "") return $err;
765  // compute new id
766  if ($this->id == "") {
767  if ($this->doctype == 'T') $res = pg_exec($this->init_dbid() , "select nextval ('seq_id_tdoc')");
768  else $res = pg_exec($this->init_dbid() , "select nextval ('seq_id_doc')");
769  $arr = pg_fetch_array($res, 0);
770  $this->id = $arr[0];
771  }
772  // set default values
773  if ($this->initid == "") $this->initid = $this->id;
774  $this->RefreshTitle();
775  if (chop($this->title) == "") {
776  $fdoc = $this->getFamDoc();
777  $this->title = sprintf(_("untitle %s %d") , $fdoc->title, $this->initid);
778  }
779  if ($this->doctype == "") $this->doctype = $this->defDoctype;
780  if ($this->revision == "") $this->revision = "0";
781 
782  if ($this->profid == "") $this->profid = "0";
783  if ($this->usefor == "") $this->usefor = "N";
784 
785  if ($this->lmodify == "") $this->lmodify = "N";
786  if ($this->locked == "") $this->locked = "0";
787  if ($this->owner == "") $this->owner = $this->userid;
788  // if ($this->state == "") $this->state=$this->firstState;
789  $this->version = $this->getVersion();
790 
791  if ($this->wid > 0) {
792  $this->wdoc = new_Doc($this->dbaccess, $this->wid);
793  if ($this->wdoc->isAlive()) {
794  if ($this->wdoc->doctype != 'W') $err = sprintf(_("creation : document %s is not a workflow") , $this->wid);
795  else $this->wdoc->Set($this); // set first state
796 
797  } else $err = sprintf(_("creation : workflow %s not exists") , $this->wid);
798  }
799  return $err;
800  }
801  /**
802  * Verify control edit
803  *
804  * if {@link disableEditControl()} is call before control permission is desactivated
805  * if attribute values are changed the modification date is updated
806  * @return string error message, if no error empty string
807  */
808  function PreUpdate()
809  {
810  if ($this->id == "") return _("cannot update no initialized document");
811  if ($this->doctype == 'I') return _("cannot update inconsistent document"); // provides from waiting document
812  if (!$this->withoutControl) {
813  $err = $this->control("edit");
814  if ($err != "") return ($err);
815  }
816  if ($this->locked == - 1) $this->lmodify = 'N';
817  if ($this->isFixed()) return _("cannot update fixed document");
818  if ($this->constraintbroken) return (sprintf(_("constraint broken %s") , $this->constraintbroken));
819  $this->RefreshTitle();
820  if ($this->hasChanged) {
821  if (chop($this->title) == "") $this->title = _("untitle document");
822  // set modification date
823  $date = gettimeofday();
824  $this->revdate = $date['sec'];
825  $this->version = $this->getVersion();
826  $this->lmodify = 'Y';
827  // $this->postModify(); // in modcard function
828 
829  }
830  }
831  /**
832  * optimize for speed : memorize object for future use
833  * @global array optimize for speed :: reference is not a pointer !!
834  */
835  function PostUpdate()
836  {
837  global $gdocs; // optimize for speed :: reference is not a pointer !!
838  //unset($gdocs[$this->id]); // clear cache
839  if (isset($gdocs[$this->id])) {
840  if ($this->nocache) unset($gdocs[$this->id]); // clear cache
841  else $gdocs[$this->id] = $this; // update caches
842 
843  }
844 
845  if ($this->hasChanged) {
846  $this->computeDProfil();
847  $this->regenerateTemplates();
848  $this->UpdateVaultIndex();
849  $this->updateRelations();
850  if ($this->getATag("DYNTIMER")) $this->resetDynamicTimers();
851  $this->addLog("changed", array_keys($this->getOldValues()));
852  }
853  $this->sendTextToEngine();
854  $this->hasChanged = false;
855  }
856  /**
857  * Regenerate the template referenced by an attribute
858  *
859  * @param string $aid the name of the attribute holding the template
860  * @param string $index the value for $index row (default value -1 means all values)
861  * @return string error message, if no error empty string
862  */
863  function regenerateTemplate($aid, $index = - 1)
864  {
865  $layout = 'THIS:' . $aid;
866  if ($index > - 1) {
867  $layout.= '[' . $index . ']';
868  }
869  $orifile = $this->getZoneFile($layout);
870  if (!$orifile) {
871  $err = sprintf(_("Dynamic template %s not found ") , $orifile);
872  return $err;
873  }
874  if (!file_exists($orifile)) {
875  $err = sprintf(_("Dynamic template %s not found ") , $orifile);
876  addWarningMsg($err);
877  return $err;
878  }
879  if (getFileExtension($orifile) != 'odt') {
880  $err = sprintf(_("Dynamic template %s not an odt file ") , $orifile);
881  addWarningMsg($err);
882  return $err;
883  }
884  $outfile = $this->viewDoc($layout . ':B', 'ooo');
885  if (!file_exists($outfile)) {
886  $err = sprintf(_("viewDoc did not returned a valid file"));
887  addWarningMsg($err);
888  return $err;
889  }
890  $fh = fopen($outfile, 'rb');
891  if ($fh === false) {
892  $err = sprintf(_("Error opening %s file '%s'", 'outfile', $outfile));
893  addWarningMsg($err);
894  return $err;
895  }
896  $err = $this->saveFile($aid, $fh, '', $index);
897  if ($err != '') {
898  addWarningMsg($err);
899  return $err;
900  }
901  fclose($fh);
902  $this->AddComment(sprintf(_('regeneration of file template %s') , $aid));
903  return '';
904  }
905  /**
906  * Regenerate all templates referenced by the document attributes
907  *
908  * @return string error message, if no error empty string
909  */
910  final function regenerateTemplates()
911  {
912  $fa = $this->GetFileAttributes();
913  $errorList = array();
914  foreach ($fa as $aid => $oattr) {
915  $opt = $oattr->getOption("template");
916  if ($opt == "dynamic" || $opt == "form") {
917  if ($oattr->inArray()) {
918  $ta = $this->getTValue($aid);
919  foreach ($ta as $k => $v) {
920  $err = $this->regenerateTemplate($aid, $k);
921  if ($err != '') {
922  array_push($errorList, $err);
923  }
924  }
925  } else {
926  $err = $this->regenerateTemplate($aid);
927  if ($err != '') {
928  array_push($errorList, $err);
929  }
930  }
931  }
932  }
933  if (count($errorList) > 0) {
934  return join("\n", $errorList);
935  }
936  return '';
937  }
938  /**
939  * Set relation doc id use on docrel table
940  */
941  function updateRelations($force = false)
942  {
943  // return; // for the moment
944  include_once ("FDL/Class.DocRel.php");
945  $or = new DocRel($this->dbaccess);
946  // $or->resetRelations('',$this->initid); // not necessary now
947  $or->initRelations($this, $force);
948  }
949  /**
950  * get current sequence number :: number of doc for this family
951  * @return int
952  */
953  function getCurSequence()
954  {
955  if ($this->doctype == 'C') return 0;
956  if ($this->fromid == "") return 0;
957  // cannot use currval if nextval is not use before
958  $res = pg_exec($this->init_dbid() , "select nextval ('seq_doc" . $this->fromid . "')");
959  $arr = pg_fetch_array($res, 0);
960  $cur = intval($arr[0]) - 1;
961  $res = pg_exec($this->init_dbid() , "select setval ('seq_doc" . $this->fromid . "',$cur)");
962 
963  return $cur;
964  }
965  // set next sequence family
966  function nextSequence($fromid = 0)
967  {
968  if ($fromid == 0) $fromid = $this->fromid;
969  if ($this->fromid == 0) return 0;
970  if ($this->doctype == 'C') return 0;
971  // cannot use currval if nextval is not use before
972  $res = pg_exec($this->init_dbid() , "select nextval ('seq_doc" . $fromid . "')");
973  $arr = pg_fetch_array($res, 0);
974  $cur = intval($arr[0]);
975  return $cur;
976  }
977  /**
978  * modify without edit control
979  */
980  final public function disableEditControl()
981  {
982  $this->withoutControlN++;
983  $this->withoutControl = true;
984  }
985  /**
986  * default edit control enable
987  */
988  final public function enableEditControl()
989  {
990  $this->withoutControlN--;
991  if ($this->withoutControlN <= 0) {
992  $this->withoutControlN = 0;
993  $this->withoutControl = false;
994  }
995  }
996  /**
997  * to know if the document can be revised
998  *
999  * @return bool true is revisable
1000  */
1001  public function isRevisable()
1002  {
1003  if (($this->doctype == 'F') && ($this->usefor != 'P')) {
1004  $fdoc = $this->getFamDoc();
1005  if ($fdoc->schar != "S") return true;
1006  }
1007  return false;
1008  }
1009  /**
1010  * copy values from anothers document (must be same family or descendant)
1011  *
1012  * @param Doc &$from document source for the transfert
1013  */
1014  final public function transfertValuesFrom(&$from)
1015  {
1016 
1017  $values = $from->getValues();
1018 
1019  foreach ($values as $k => $v) {
1020  $this->setValue($k, $v);
1021  }
1022  }
1023  /**
1024  * convert to another family
1025  * loose all revisions
1026  * @param int $fromid family identificator where the document will be converted
1027  * @param array $prevalues values which will be added before conversion
1028  * @return doc the document converted (don't reuse $this) if error return string message
1029  */
1030  final public function convert($fromid, $prevalues = array())
1031  {
1032 
1033  $cdoc = createDoc($this->dbaccess, $fromid);
1034  if (!$cdoc) return false;
1035  if ($this->fromid == $cdoc->fromid) return false; // no convert if not needed
1036  if ($this->locked == - 1) return false; // not revised document
1037  if ($cdoc->fromid == 0) return false;
1038  $f1doc = $this->getFamDoc();
1039  $f1from = $f1doc->title . "[" . $f1doc->id . "]";
1040  $f2doc = $cdoc->getFamDoc();
1041  $f2from = $f2doc->title . "[" . $f2doc->id . "]";
1042 
1043  $cdoc->id = $this->id;
1044  $cdoc->initid = $this->id;
1045  $cdoc->revision = 0;
1046  $cdoc->cdate = $this->cdate;
1047  $cdoc->revdate = $this->revdate;
1048  $cdoc->adate = $this->adate;
1049  $cdoc->locked = $this->locked;
1050  $cdoc->profid = $this->profid;
1051  $cdoc->dprofid = $this->dprofid;
1052  $cdoc->prelid = $this->prelid;
1053 
1054  $values = $this->getValues();
1055  $point = "convert" . $this->id;
1056  $this->savePoint($point); // begin transaction in case of fail add
1057  $err = $this->delete(true, false, true); // delete before add to avoid double id (it is not authorized)
1058  if ($err != "") return $err;
1059 
1060  foreach ($prevalues as $k => $v) {
1061  $cdoc->setValue($k, $v);
1062  }
1063  $err = $cdoc->Add(true, true);
1064  if ($err != "") {
1065  $this->rollbackPoint($point);
1066  return $err;
1067  }
1068 
1069  foreach ($values as $k => $v) {
1070  $cdoc->setValue($k, $v);
1071  }
1072 
1073  $err = $cdoc->Modify();
1074  if ($err == "") {
1075  if ($this->revision > 0) {
1076  $this->exec_query(sprintf("update fld set childid=%d where childid=%d", $cdoc->id, $this->initid));
1077  }
1078  }
1079  $this->exec_query(sprintf("update fld set fromid=%d where childid=%d", $cdoc->fromid, $this->initid));
1080 
1081  $cdoc->AddComment(sprintf(_("convertion from %s to %s family") , $f1from, $f2from));
1082 
1083  $this->commitPoint($point);
1084  global $gdocs; //reset cache if needed
1085  if (isset($gdocs[$this->id])) {
1086  $gdocs[$this->id] = & $cdoc;
1087  }
1088 
1089  return $cdoc;
1090  }
1091  /**
1092  * test if the document can be revised now
1093  * it must be locked by the current user
1094  * @deprecated
1095  * @return string empty means user can update else message of the raison
1096  */
1097  final public function canUpdateDoc()
1098  {
1100  return $this->canEdit();
1101  }
1102  /**
1103  * save document if attribute are change
1104  * not be use when modify properties
1105  * only use with use of setValue.
1106  * @param stdClass $info refresh and postModify messages
1107  * @param boolean $skipConstraint set to true to not test constraints
1108  * @deprecated use ::store() instead
1109  * @return string error message
1110  */
1111  public function save(&$info = null, $skipConstraint = false)
1112  {
1114  $err = '';
1115  $info = '';
1116  $info->constraint = '';
1117  if (!$skipConstraint) {
1118  $err = $this->verifyAllConstraints(false, $info->constraint);
1119  }
1120  if ($err == '') {
1121  $info->refresh = $this->refresh();
1122  $info->postModify = $this->postModify();
1123  if ($this->hasChanged) {
1124  //in case of change in postModify
1125  $err = $this->modify();
1126  }
1127  if ($err == "") $this->addComment(_("save document") , HISTO_INFO, "MODIFY");
1128  }
1129  $info->error = $err;
1130  return $err;
1131  }
1132  /**
1133  * record new document or update
1134  * @param stdClass $info refresh and postModify messages
1135  * @param boolean $skipConstraint set to true to not test constraints
1136  * @return string error message
1137  */
1138  public function store(&$info = null, $skipConstraint = false)
1139  {
1140  $err = '';
1141  $constraint = '';
1142  $info = '';
1143 
1144  if (!$skipConstraint) {
1145  $err = $this->verifyAllConstraints(false, $constraint);
1146  }
1147  if ($err == '') {
1148  $create = false;
1149  if (!$this->isAffected()) {
1150  $err = $this->add();
1151  $create = true;
1152  }
1153  if ($err == '') {
1154  $info->refresh = $this->refresh();
1155  $info->postModify = $this->postModify();
1156  if ($this->hasChanged) {
1157  //in case of change in postModify
1158  $err = $this->modify();
1159  }
1160  if ($err == "" && (!$create)) $this->addComment(_("save document") , HISTO_INFO, "MODIFY");
1161  }
1162  }
1163  $info->constraint = $constraint;
1164  $info->error = $err;
1165  return $err;
1166  }
1167  /**
1168  * test if the document can be edit by the current user
1169  * the diffence between ::canUpdateDoc is that document is not need to be locked
1170  * @return string empty means user can update else message of the raison
1171  */
1172  public function canEdit($verifyDomain = true)
1173  {
1174  if ($this->locked == - 1) {
1175  $err = sprintf(_("cannot update file %s (rev %d) : fixed. Get the latest version") , $this->title, $this->revision);
1176  return ($err);
1177  }
1178  if ($this->userid == 1) return ""; // admin can do anything but not modify fixed doc
1179  $err = "";
1180  if ($verifyDomain && ($this->lockdomainid > 0)) $err = sprintf(_("document is booked in domain %s") , $this->getTitle($this->lockdomainid));
1181  else {
1182  if ($this->withoutControl) return ""; // no more test if disableEditControl activated
1183  if (($this->locked != 0) && (abs($this->locked) != $this->userid)) {
1184  $user = new User("", abs($this->locked));
1185  if ($this->locked < - 1) $err = sprintf(_("Document %s is in edition by %s.") , $this->getTitle() , $user->firstname . " " . $user->lastname);
1186  else $err = sprintf(_("you are not allowed to update the file %s (rev %d) is locked by %s.") , $this->getTitle() , $this->revision, $user->firstname . " " . $user->lastname);
1187  } else {
1188  $err = $this->Control("edit");
1189  }
1190  }
1191  return ($err);
1192  }
1193  /**
1194  * test if the document can be locked
1195  * it is not locked before, and the current user can edit document
1196  * @return string empty means user can update else message of the raison
1197  */
1198  final public function CanLockFile()
1199  {
1200  $err = $this->canEdit();
1201 
1202  return ($err);
1203  }
1204  /**
1205  * @return boolean true if can lock file
1206  */
1207  public function canLock()
1208  {
1209  return ($this->CanLockFile() == "");
1210  }
1211  /**
1212  * @return boolean true if can lock file
1213  */
1214  public function canUnLock()
1215  {
1216  return ($this->CanUnLockFile() == "");
1217  }
1218  /**
1219  * test if the document can be unlocked
1220  * @see CanLockFile()
1221  * @see CanUpdateDoc()
1222  * @return string empty means user can update else message of the raison
1223  */
1224  final public function CanUnLockFile()
1225  {
1226  if ($this->userid == 1) return ""; // admin can do anything
1227  $err = "";
1228  if ($this->locked != 0) { // if is already unlocked
1229  if ($this->profid > 0) $err = $this->Control("unlock"); // first control unlock privilege
1230  else $err = _("cannot unlock"); // not control unlock if the document is not controlled
1231 
1232  }
1233  if ($err != "") $err = $this->canEdit();
1234  else {
1235  $err = $this->Control("edit");
1236  if ($err != "") {
1237  if ($this->profid > 0) {
1238  $err = $this->Control("unlock");
1239  }
1240  }
1241  }
1242  return ($err);
1243  }
1244  /**
1245  * test if the document is locked
1246  * @see CanLockFile()
1247  * @param bool $my if true test if it is lock of current user
1248  *
1249  * @return bool true if locked. If $my return true if it is locked by another user
1250  */
1251  final public function isLocked($my = false)
1252  {
1253  if ($my) {
1254  if (($this->user->id == 1) || (abs($this->locked) == $this->userid)) return false;
1255  }
1256  return (($this->locked > 0) || ($this->locked < - 1));
1257  }
1258  /**
1259  * test if the document is confidential
1260  *
1261  * @return bool true if confidential and current user is not authorized
1262  */
1263  final public function isConfidential()
1264  {
1265  return (($this->confidential > 0) && ($this->controlId($this->profid, 'confidential') != ""));
1266  }
1267  /**
1268  * return the family document where the document comes from
1269  *
1270  * @return DocFam
1271  */
1272  final public function getFamDoc()
1273  {
1274  if (!isset($this->famdoc) || ($this->famdoc->id != $this->fromid)) $this->famdoc = new_Doc($this->dbaccess, $this->fromid);
1275  return $this->famdoc;
1276  }
1277  /**
1278  * search the first document from its title
1279  * @param string $title the title to search (must be exactly the same title)
1280  * @return int document identificator
1281  */
1283  {
1284 
1285  $query = new QueryDb($this->dbaccess, "Doc");
1286  $query->basic_elem->sup_where = array(
1287  "title='" . $title . "'"
1288  );
1289 
1290  $table1 = $query->Query();
1291  $id = 0;
1292  if ($query->nb > 0) {
1293  $id = $table1[0]->id;
1294 
1295  unset($table1);
1296  }
1297  return $id;
1298  }
1299  /**
1300  * return family parameter
1301  *
1302  * @param string $idp parameter identificator
1303  * @param string $def default value if parameter not found or if it is null
1304  * @return string parameter value
1305  */
1306  public function getParamValue($idp, $def = "")
1307  {
1308  if ($this->doctype == 'C') return $this->getParamValue($idp, $def);
1309  if (!$this->fromid) return false;
1310  $fdoc = $this->getFamDoc();
1311  if (!$fdoc->isAlive()) return false;
1312  return $fdoc->getParamValue($idp, $def);
1313  }
1314  /**
1315  * return similar documents
1316  *
1317  * @param string $key1 first attribute id to perform search
1318  * @param string $key2 second attribute id to perform search
1319  * @return string parameter value
1320  */
1321  final public function GetDocWithSameTitle($key1 = "title", $key2 = "")
1322  {
1323  include_once ("FDL/Lib.Dir.php");
1324  // --------------------------------------------------------------------
1325  $filter[] = "doctype!='T'";
1326  if ($this->initid > 0) $filter[] = "initid !='" . $this->initid . "'"; // not itself
1327  $filter[] = "$key1='" . addslashes($this->getValue($key1)) . "'";
1328  if ($key2 != "") $filter[] = "$key2='" . addslashes($this->getValue($key2)) . "'";
1329  $tpers = getChildDoc($this->dbaccess, 0, 0, "ALL", $filter, 1, "LIST", $this->fromid);
1330 
1331  return $tpers;
1332  }
1333  /**
1334  * return the latest revision id with the indicated state
1335  * For the user the document is in the trash
1336  * @param string $state wanted state
1337  * @param bool $fixed set to true if not search in current state
1338  * @return int document id (0 if no found)
1339  */
1340  final public function getRevisionState($state, $fixed = false)
1341  {
1342  $ldoc = $this->GetRevisions("TABLE");
1343  $vdocid = 0;
1344 
1345  foreach ($ldoc as $k => $v) {
1346  if ($v["state"] == $state) {
1347  if ((($v["locked"] == - 1) && $fixed) || (!$fixed)) {
1348  $vdocid = $v["id"];
1349  break;
1350  }
1351  }
1352  }
1353  return $vdocid;
1354  }
1355  // --------------------------------------------------------------------
1356  final public function DeleteTemporary()
1357  {
1358  // --------------------------------------------------------------------
1359  $result = pg_exec($this->init_dbid() , "delete from doc where doctype='T'");
1360  }
1361  /**
1362  * Control if the doc can be deleted
1363  * @access private
1364  * @return string error message, if no error empty string
1365  * @see Doc::Delete()
1366  */
1367  function PreDocDelete()
1368  {
1369  if ($this->doctype == 'Z') return _("already deleted");
1370  if ($this->isLocked(true)) return _("locked");
1371  if ($this->lockdomainid > 0) return sprintf(_("document is booked in domain %s") , $this->getTitle($this->lockdomainid));
1372  $err = $this->Control("delete");
1373 
1374  return $err;
1375  }
1376  /**
1377  * Really delete document from database
1378  * @return string error message, if no error empty string
1379  */
1380  final public function ReallyDelete($nopost)
1381  {
1382  $err = DbObj::delete($nopost);
1383  if ($err == "") {
1384  $dvi = new DocVaultIndex($this->dbaccess);
1385  $err = $dvi->DeleteDoc($this->id);
1386  if ($this->name != '') {
1387  $this->exec_query(sprintf("delete from docname where name='%s'", pg_escape_string($this->name)));
1388  }
1389  $this->exec_query(sprintf("delete from docfrom where id='%s'", pg_escape_string($this->id)));
1390  }
1391  return $err;
1392  }
1393  /**
1394  * Set the document to zombie state
1395  * For the user the document is in the trash
1396  * @param bool $really if true call {@link ReallyDelete} really delete from database
1397  * @param bool $control if false don't control 'delete' acl
1398  * @param bool $nopost if true don't call {@link PostDelete} and {@link PreDelete}
1399  * @return void
1400  */
1401  final public function Delete($really = false, $control = true, $nopost = false)
1402  {
1403 
1404  if ($control) {
1405  // Control if the doc can be deleted
1406  $msg = $this->PreDocDelete();
1407  if ($msg != '') return $msg;
1408  }
1409 
1410  if (abs(intval($this->forumid)) > 0) {
1411  $df = new_Doc($this->dbaccess, abs(intval($this->forumid)));
1412  $df->delete($really, $control, $nopost);
1413  }
1414 
1415  if ($really) {
1416  if ($this->id != "") {
1417  // delete all revision also
1418  $this->addLog('delete', array(
1419  "really" => $really
1420  ));
1421  $rev = $this->GetRevisions();
1422  foreach ($rev as $k => $v) {
1423  $v->ReallyDelete($nopost);
1424  }
1425  }
1426  } else {
1427  // Control if the doc can be deleted
1428  if ($this->doctype == 'Z') $msg = _("already deleted");
1429  if ($msg != '') return $msg;
1430 
1431  if (!$nopost) $msg = $this->PreDelete();
1432  if ($msg != '') return $msg;
1433 
1434  if ($this->doctype != 'Z') {
1435 
1436  if ($this->name != "") $this->exec_query(sprintf("delete from doc%d where name='%s' and doctype='Z'", $this->fromid, pg_escape_string($this->name))); // need to not have twice document with same name
1437  $this->doctype = 'Z'; // Zombie Doc
1438  $this->locked = - 1;
1439  $this->lmodify = 'D'; // indicate last delete revision
1440  $date = gettimeofday();
1441  $this->revdate = $date['sec']; // Delete date
1442  global $action;
1443  global $_SERVER;
1444  $this->AddComment(sprintf(_("delete by action %s/%s from %s") , $action->parent->name, $action->name, $_SERVER["REMOTE_ADDR"]) , HISTO_NOTICE);
1445  $this->addComment(_("document deleted") , HISTO_MESSAGE, "DELETE");
1446  $this->addLog('delete', array(
1447  "really" => $really
1448  ));
1449 
1450  $this->modify(true, array(
1451  "doctype",
1452  "revdate",
1453  "locked",
1454  "owner",
1455  "lmodify"
1456  ) , true);
1457  if (!$nopost) $msg = $this->PostDelete();
1458  // delete all revision also
1459  $rev = $this->GetRevisions();
1460  foreach ($rev as $k => $v) {
1461  if ($v->doctype != 'Z') {
1462  $v->doctype = 'Z'; // Zombie Doc
1463  if ($v->locked == - 1) $v->modify(true, array(
1464  "doctype"
1465  ) , true);
1466  }
1467  }
1468  }
1469  return $msg;
1470  }
1471  }
1472  /**
1473  * To restore a document which is in the trash
1474  * @return string error message (empty message if no errors);
1475  */
1476  final public function revive()
1477  {
1478  $err = "";
1479  if (($this->control('delete') == "") || ($this->userid == 1)) {
1480  if (!$this->isAlive()) {
1481  $err = simpleQuery($this->dbaccess, sprintf("SELECT id from only doc%d where initid = %d order by id desc limit 1", $this->fromid, $this->initid) , $latestId, true, true);
1482  if ($err == "") {
1483  if (!$latestId) $err = sprintf(_("document %s [%d] is strange") , $this->title, $this->id);
1484  else {
1485  $this->doctype = $this->defDoctype;
1486  $this->locked = 0;
1487  $this->id = $latestId;
1488  $this->lmodify = 'Y'; // indicate last restoration
1489  $this->modify(true, array(
1490  "doctype",
1491  "locked",
1492  "lmodify"
1493  ) , true);
1494  $this->AddComment(_("revival document") , HISTO_MESSAGE, "REVIVE");
1495 
1496  $this->addLog('revive');
1497  $rev = $this->getRevisions();
1498  foreach ($rev as $k => $v) {
1499  if ($v->doctype == 'Z') {
1500  $v->doctype = $v->defDoctype;
1501  $err.= $v->modify(true, array(
1502  "doctype"
1503  ) , true);
1504  }
1505  }
1506  if ($this->name) {
1507  // force reset logival name if not set
1508  $name = $this->name;
1509  $this->name = '';
1510  $this->modify(true, array(
1511  "name"
1512  ) , true);
1514  }
1515  }
1516  }
1517  } else return sprintf(_("document %s [%d] is not in the trash") , $this->getTitle() , $this->id);
1518  } else return sprintf(_("need privilege delete to restore %s") , $this->getTitle());
1519  return $err;
1520  }
1521  /**
1522  * Adaptation of affect Method from DbObj because of inheritance table
1523  * this function is call from QueryDb and all fields can not be instanciate
1524  * @param array $array the data array
1525  * @param bool $more add values from values attributes needed only if cast document
1526  * @return void
1527  */
1528  final public function Affect($array, $more = false)
1529  {
1530  if (is_array($array)) {
1531  if ($more) $this->ResetMoreValues();
1532  unset($this->uperm); // force recompute privileges
1533  foreach ($array as $k => $v) {
1534  if (!is_integer($k)) {
1535  $this->$k = $v;
1536  }
1537  }
1538  $this->Complete();
1539  if ($more) $this->GetMoreValues();
1540 
1541  $this->isset = true;
1542  }
1543  }
1544  /**
1545  * Set to default values before add new doc
1546  * @return void
1547  */
1548  function Init()
1549  {
1550  $this->isset = false;
1551  $this->id = "";
1552  $this->initid = "";
1553  $this->comment = "";
1554  $nattr = $this->GetNormalAttributes();
1555  foreach ($nattr as $k => $v) {
1556  if (isset($this->$k) && ($this->$k != "")) $this->$k = "";
1557  }
1558  unset($this->lvalues);
1559  }
1560  // --------------------------------------------------------------------
1561  function Description()
1562  {
1563  // --------------------------------------------------------------------
1564  return $this->title . " - " . $this->revision;
1565  }
1566  // --------------------------------------------------------------------
1567  final public function GetFathersDoc()
1568  {
1569  // --------------------------------------------------------------------
1570  // Return array of father doc id : class document
1571  if (!isset($this->fathers)) {
1572 
1573  $this->fathers = array();
1574  if ($this->fromid > 0) {
1575  $fdoc = $this->getFamDoc();
1576  $this->fathers = $fdoc->GetFathersDoc();
1577  array_push($this->fathers, $this->fromid);
1578  }
1579  }
1580  return $this->fathers;
1581  }
1582  /**
1583  * Return array of fathers doc id : class document
1584  * @return array
1585  */
1586  final public function GetFromDoc()
1587  {
1588  return $this->attributes->fromids;
1589  }
1590  /**
1591  * Return array of child doc id : class document
1592  * @return array
1593  */
1594  final public function GetChildFam($id = - 1, $controlcreate = false)
1595  {
1596  if ($id == 0) return array();
1597  if (($id != - 1) || (!isset($this->childs))) {
1598  include_once ("FDL/Class.SearchDoc.php");
1599  if ($id == - 1) $id = $this->id;
1600  if (!isset($this->childs)) $this->childs = array();
1601 
1602  $s = new SearchDoc($this->dbaccess, -1);
1603  $s->addFilter("fromid = " . $id);
1604  $s->noViewControl();
1605  $table1 = $s->search();
1606  if ($table1) {
1607  foreach ($table1 as $k => $v) {
1608  if ((!$controlcreate) || controlTdoc($v, "icreate")) {
1609  $this->childs[$v["id"]] = $v;
1610  }
1611  $this->GetChildFam($v["id"], $controlcreate);
1612  }
1613  }
1614  }
1615  return $this->childs;
1616  }
1617  /**
1618  * return all revision documents
1619  */
1620  final public function GetRevisions($type = "LIST", $limit = 200)
1621  {
1622  // Return the document revision
1623  $query = new QueryDb($this->dbaccess, strtolower(get_class($this)));
1624  //$query->AddQuery("revision <= ".$this->revision);
1625  $query->AddQuery("initid = " . $this->initid);
1626  $query->order_by = "revision DESC LIMIT $limit";
1627 
1628  $rev = $query->Query(0, 0, $type);
1629  if ($query->nb == 0) return array();
1630  return $rev;
1631  }
1632  /** get Latest Id of document
1633  *
1634  * @param bool $fixed if true latest fixed revision
1635  * @param bool $forcequery if true force recompute of id (use it in case of modification by another program)
1636  * @return int identificator of latest revision
1637  */
1638  final public function latestId($fixed = false, $forcequery = false)
1639  {
1640  if ($this->id == "") return false;
1641  if (!$forcequery) {
1642  if (($this->locked != - 1) && (!$fixed)) return $this->id;
1643  if ($fixed && ($this->lmodify == "L")) return $this->id;
1644  }
1645  if (!$fixed) return getLatestDocId($this->dbaccess, $this->initid);
1646  $query = new QueryDb($this->dbaccess, strtolower(get_class($this)));
1647  $query->AddQuery("initid = " . $this->initid);
1648  if ($fixed) $query->AddQuery("lmodify = 'L'");
1649  elseif ($this->doctype != 'Z') $query->AddQuery("locked != -1");
1650  else {
1651  $query->order_by = "id desc";
1652  }
1653  $rev = $query->Query(0, 2, "TABLE");
1654 
1655  if ($this->doctype != 'Z') {
1656  if (count($rev) > 1) addWarningMsg(sprintf("document %d : multiple alive revision", $this->initid));
1657  }
1658  return $rev[0]["id"];
1659  }
1660  /**
1661  * get version of document
1662  * must be redefined by child document classes if needed
1663  * @return string
1664  */
1665  final public function getVersion()
1666  {
1667  $tversion = array();
1668  if (isset($this->attributes->attr)) {
1669  foreach ($this->attributes->attr as $k => $v) {
1670  if ((get_class($v) == "NormalAttribute") && ($v->getOption("version") == "yes")) {
1671  $tversion[] = $this->getValue($v->id);
1672  }
1673  }
1674  }
1675  if (count($tversion) > 0) $version = implode(" ", $tversion);
1676  else $version = $this->version;
1677  return $version;
1678  }
1679  /**
1680  * return the string label text for a id
1681  * @return string
1682  */
1683  final public function getLabel($idAttr)
1684  {
1685  if (isset($this->attributes->attr[$idAttr])) return $this->attributes->attr[$idAttr]->getLabel();
1686  return _("unknow attribute");
1687  }
1688  /**
1689  * return the property object like id, initid, revision, ...
1690  * @param string $idAttr attribute identificator
1691  * @return string false if not an property
1692  */
1693  final public function getProperty($prop)
1694  {
1695  $prop = trim(strtolower($prop));
1696  if (!in_array($prop, $this->fields)) return false;
1697  if (isset($this->fields[$prop])) return false; // it's an attribute
1698  return $this->$prop;
1699  }
1700  /**
1701  * return the attribute object for a id
1702  * the attribute can be defined in fathers
1703  * @param string $idAttr attribute identificator
1704  * @param DocAttribute &$oa object reference use this if want to modify attribute
1705  * @return DocAttribute
1706  */
1707  final public function &getAttribute($idAttr, &$oa = null)
1708  {
1709  if (!$this->_maskApplied) $this->ApplyMask();
1710  $idAttr = strtolower($idAttr);
1711  $oas = $this->getAttributes();
1712  $oa = $oas[$idAttr];
1713  if (isset($this->attributes->attr[$idAttr])) return $oa;
1714 
1715  return false;
1716  }
1717  /**
1718  * return all the attributes object
1719  * the attribute can be defined in fathers
1720  * @return array DocAttribute
1721  */
1722  final public function &getAttributes()
1723  {
1724  $fromname = ($this->doctype == 'C') ? $this->name : $this->fromname;
1725  if ($this->attributes->fromname != $fromname) {
1726  // reset when use partial cache
1727  $fromid = ($this->doctype == 'C') ? $this->id : $this->fromid;
1728  $adocClassName = "ADoc" . $fromid;
1729  $classname = "Doc" . $fromid;
1730  $GEN = getGen($this->dbaccess);
1731  $includePath = "FDL$GEN/Class.$classname.php";
1732  if (file_exists($includePath)) {
1733  include_once ($includePath);
1734  $this->attributes = new $adocClassName();
1735  }
1736  }
1737  if (!$this->_maskApplied) $this->ApplyMask();
1738  reset($this->attributes->attr);
1739  return $this->attributes->attr;
1740  }
1741  /**
1742  * retrieve first compatible view from default view control
1743  * @param bool $edition if true edition view else consultation view
1744  * @param string $extract [id|mask|all]
1745  * @return array view definition "cv_idview", "cv_mskid"
1746  */
1747  final public function getDefaultView($edition = false, $extract = "all")
1748  {
1749  $vid = 0;
1750  if ($this->cvid > 0) {
1751  // special controlled view
1752  $cvdoc = new_Doc($this->dbaccess, $this->cvid);
1753  $cvdoc->set($this);
1754 
1755  $view = $cvdoc->getPrimaryView($edition);
1756 
1757  if ($view) {
1758  switch ($extract) {
1759  case 'id':
1760  return $view["cv_idview"];
1761  case 'mask':
1762  return $view["cv_mskid"];
1763  default:
1764  return $view;
1765  }
1766  }
1767  }
1768  return 0;
1769  }
1770  /**
1771  * set visibility mask
1772  *
1773  * @param int $mid mask ident
1774  */
1775  final public function setMask($mid)
1776  {
1777  $this->mid = $mid;
1778  if (isset($this->attributes->attr)) {
1779  // reinit mask before apply
1780  foreach ($this->attributes->attr as $k => $v) {
1781  $this->attributes->attr[$k]->mvisibility = $v->visibility;
1782  }
1783  }
1784  $this->ApplyMask($mid);
1785  }
1786  /**
1787  * apply visibility mask
1788  *
1789  * @param int $mid mask ident, if not set it is found from possible workflow
1790  */
1791  final public function ApplyMask($mid = 0, $force = false)
1792  {
1793  // copy default visibilities
1794  $this->_maskApplied = true;
1795  $oas = $this->getAttributes();
1796  if (is_array($oas)) {
1797  foreach ($oas as $k => $v) {
1798  if ($oas[$k]) $oas[$k]->mvisibility = ComputeVisibility($v->visibility, $v->fieldSet->mvisibility, ($v->fieldSet->fieldSet) ? $v->fieldSet->fieldSet->mvisibility : '');
1799  }
1800  }
1801  if ((!$force) && (($this->doctype == 'C') || (($this->doctype == 'T') && ($mid == 0)))) return;
1802  // modify visibilities if needed
1803  if ((!is_numeric($mid)) && ($mid != "")) $mid = getIdFromName($this->dbaccess, $mid);
1804  if ($mid == 0) $mid = $this->mid;
1805  if ($mid == 0) {
1806  if (($this->wid > 0) && ($this->wid != $this->id)) {
1807  // search mask from workflow
1808  $wdoc = new_Doc($this->dbaccess, $this->wid);
1809  if ($wdoc->isAlive()) {
1810  if ($this->id == 0) {
1811  $wdoc->set($this);
1812  }
1813  $mid = $wdoc->getValue($wdoc->attrPrefix . "_MSKID" . $this->state);
1814  if ((!is_numeric($mid)) && ($mid != "")) $mid = getIdFromName($this->dbaccess, $mid);
1815  }
1816  }
1817  }
1818  if ($mid > 0) {
1819 
1820  $mdoc = new_Doc($this->dbaccess, $mid);
1821  if ($mdoc->isAlive()) {
1822  $tvis = $mdoc->getCVisibilities();
1823  foreach ($tvis as $k => $v) {
1824  if (isset($oas[$k])) {
1825  if ($v != "-") $oas[$k]->mvisibility = $v;
1826  }
1827  }
1828  $tdiff = array_diff(array_keys($oas) , array_keys($tvis));
1829  // recompute loosed attributes
1830  foreach ($tdiff as $k) {
1831  $v = $oas[$k];
1832  $oas[$k]->mvisibility = ComputeVisibility($v->visibility, $v->fieldSet->mvisibility, ($v->fieldSet->fieldSet) ? $v->fieldSet->fieldSet->mvisibility : '');
1833  }
1834  // modify needed attribute also
1835  $tneed = $mdoc->getNeedeeds();
1836  foreach ($tneed as $k => $v) {
1837  if (isset($oas[$k])) {
1838  if ($v == "Y") $oas[$k]->needed = true;
1839  else if ($v == "N") $oas[$k]->needed = false;
1840  }
1841  }
1842  }
1843  }
1844  uasort($this->attributes->attr, "tordered");
1845  }
1846  /**
1847  * return all the attributes except frame & menu & action
1848  *
1849  * @return array DocAttribute
1850  */
1851  final public function GetNormalAttributes($onlyopt = false)
1852  {
1853  if (!$this->_maskApplied) $this->ApplyMask();
1854  if ((isset($this->attributes)) && (method_exists($this->attributes, "GetNormalAttributes"))) return $this->attributes->GetNormalAttributes($onlyopt);
1855  else return array();
1856  }
1857  /**
1858  * return frame attributes
1859  *
1860  * @return array FieldSetAttribute
1861  */
1862  final public function GetFieldAttributes()
1863  {
1864  if (!$this->_maskApplied) $this->ApplyMask();
1865  $tsa = array();
1866 
1867  foreach ($this->attributes->attr as $k => $v) {
1868  if (get_class($v) == "FieldSetAttribute") $tsa[$v->id] = $v;
1869  }
1870  return $tsa;
1871  }
1872  /**
1873  * return action attributes
1874  *
1875  * @return array ActionAttribute
1876  */
1877  final public function GetActionAttributes()
1878  {
1879  if (!$this->_maskApplied) $this->ApplyMask();
1880  $tsa = array();
1881  $at = $this->attributes->GetActionAttributes();
1882  foreach ($at as $k => $v) {
1883  if ($v->mvisibility != 'H') $tsa[$v->id] = $v;
1884  }
1885  return $tsa;
1886  }
1887  /**
1888  * return all the attributes object for abstract
1889  * the attribute can be defined in fathers
1890  * @return array DocAttribute
1891  */
1892  final public function GetAbstractAttributes()
1893  {
1894  if (!$this->_maskApplied) $this->ApplyMask();
1895  $tsa = array();
1896 
1897  if (isset($this->attributes->attr)) {
1898  foreach ($this->attributes->attr as $k => $v) {
1899  if ((get_class($v) == "NormalAttribute") && ($v->usefor != 'Q') && ($v->isInAbstract)) $tsa[$v->id] = $v;
1900  }
1901  }
1902  return $tsa;
1903  }
1904  /**
1905  * return all the attributes object for title
1906  * the attribute can be defined in fathers
1907  * @return array DocAttribute
1908  */
1909  final public function GetTitleAttributes()
1910  {
1911  if (!$this->_maskApplied) $this->ApplyMask();
1912  $tsa = array();
1913  if (isset($this->attributes->attr)) {
1914  foreach ($this->attributes->attr as $k => $v) {
1915  if ((get_class($v) == "NormalAttribute") && ($v->isInTitle)) $tsa[$v->id] = $v;
1916  }
1917  }
1918  return $tsa;
1919  }
1920  /**
1921  * return all the attributes that can be use in profil
1922  *
1923  * @return array DocAttribute
1924  */
1925  final public function GetProfilAttributes()
1926  {
1927  if (!$this->_maskApplied) $this->ApplyMask();
1928  $tsa = array();
1929  $tsb = array();
1930  $wopt = false;
1931  if (isset($this->attributes->attr)) {
1932  foreach ($this->attributes->attr as $k => $v) {
1933  if ((get_class($v) == "NormalAttribute") && ($v->type == "docid")) {
1934  if ($v->getOption("isuser") != "") {
1935  if ($v->getOption("isuser") == "yes") $tsb[$v->id] = $v;
1936  $wopt = true;
1937  } else $tsa[$v->id] = $v;
1938  }
1939  }
1940  }
1941  if ($wopt) return $tsb;
1942  return $tsa;
1943  }
1944  /**
1945  * return all the attributes object for to e use in edition
1946  * the attribute can be defined in fathers
1947  * @return array DocAttribute
1948  */
1949  final public function GetInputAttributes($onlyopt = false)
1950  {
1951  if (!$this->_maskApplied) $this->ApplyMask();
1952  $tsa = array();
1953 
1954  foreach ($this->attributes->attr as $k => $v) {
1955  if ((get_class($v) == "NormalAttribute") && (!$v->inArray()) && ($v->mvisibility != "I")) { // I means not editable
1956  if ((($this->usefor == "Q") && ($v->usefor == "Q")) || (($this->usefor != "Q") && ((($v->usefor != "Q") && (!$onlyopt)) || (($v->usefor == "O") && ($onlyopt))))) $tsa[$v->id] = $v; //special parameters
1957 
1958  }
1959  }
1960  return $tsa;
1961  }
1962  /**
1963  * return all the parameters definition for its family
1964  * the attribute can be defined in fathers
1965  * @return array DocAttribute
1966  */
1967  final public function getParamAttributes()
1968  {
1969 
1970  if (!$this->_maskApplied) $this->ApplyMask();
1971  if ((isset($this->attributes)) && (method_exists($this->attributes, "getParamAttributes"))) return $this->attributes->getParamAttributes();
1972  else return array();
1973  }
1974  /**
1975  * return all the attributes object for abstract
1976  * the attribute can be defined in fathers
1977  * @param bool $onlyfile set to true if don't want images
1978  * @return array DocAttribute
1979  */
1980  final public function GetFileAttributes($onlyfile = false)
1981  {
1982  if (!$this->_maskApplied) $this->ApplyMask();
1983  $tsa = array();
1984 
1985  foreach ($this->attributes->attr as $k => $v) {
1986  if ((get_class($v) == "NormalAttribute") && ($v->usefor != 'Q') && ((($v->type == "image") && (!$onlyfile)) || ($v->type == "file"))) $tsa[$v->id] = $v;
1987  }
1988  return $tsa;
1989  }
1990  /**
1991  * return files properties of file attributes
1992  *
1993  * @return array
1994  */
1995  final public function GetFilesProperties()
1996  {
1997  $dvi = new DocVaultIndex($this->dbaccess);
1998  $tvid = $dvi->getVaultIds($this->id);
1999  $tinfo = array();
2000  $vf = newFreeVaultFile($this->dbaccess);
2001  foreach ($tvid as $vid) {
2002  $info = null;
2003  $err = $vf->Retrieve($vid, $info);
2004  $t = get_object_vars($info);
2005  $t["vid"] = $vid;
2006  if ($err == "") $tinfo[] = $t;
2007  }
2008 
2009  return $tinfo;
2010  }
2011  /**
2012  * verify if has some files waiting conversion
2013  *
2014  * @return bool
2015  */
2016  final public function hasWaitingFiles()
2017  {
2018  $dvi = new DocVaultIndex($this->dbaccess);
2019  $tvid = $dvi->getVaultIds($this->id);
2020  if (count($tvid) == 0) return false;
2021  $sql = sprintf("select id_file from vaultdiskstorage where teng_state=%d and %s limit 1", TransformationEngine::status_waiting, getSqlCond($tvid, "id_file", true));
2022  simpleQuery($this->dbaccess, $sql, $waiting, true, true);
2023  return ($waiting != false);
2024  }
2025  /**
2026  * reset Conversion of file
2027  * update $attrid_txt table column
2028  * @param string $attrid file attribute identificator
2029  * @return string error message
2030  */
2031  public function resetConvertVaultFile($attrid, $index)
2032  {
2033  $err = '';
2034  $val = $this->getTValue($attrid, false, $index);
2035  if (($index == - 1) && (count($val) == 1)) {
2036  $val = $val[0];
2037  }
2038 
2039  if ($val) {
2040  $info = $this->getFileInfo($val);
2041  if ($info) {
2042  $ofout = new VaultDiskStorage($this->dbaccess, $info["id_file"]);
2043  if ($ofout->isAffected()) {
2044  $err = $ofout->delete();
2045  }
2046  }
2047  }
2048  return $err;
2049  }
2050  /**
2051  * send a request to TE to convert fiele
2052  * update $attrid_txt table column
2053  * @param string $va value of file attribute like mime|vid
2054  * @param string $engine the name of transformation
2055  * @return new file reference
2056  */
2057  public function convertVaultFile($va, $engine, $isimage = false, $force = false)
2058  {
2059  include_once ("FDL/Lib.Vault.php");
2060  $engine = strtolower($engine);
2061  $value = '';
2062  if (is_array($va)) return "";
2063 
2064  if (getParam("TE_ACTIVATE") == "yes") {
2065  if (preg_match(PREGEXPFILE, $va, $reg)) {
2066  $vidin = $reg[2];
2067  $info = vault_properties($vidin, $engine);
2068  // in case of server not reach : try again
2069  if ($info->teng_state == TransformationEngine::error_connect) $info->teng_state = TransformationEngine::status_inprogress;
2070  if ((!$info->teng_vid) || ($info->teng_state == TransformationEngine::status_inprogress)) {
2071  $vf = newFreeVaultFile($this->dbaccess);
2072  if (!$info->teng_vid) {
2073  // create temporary file
2074  $value = sprintf(_("conversion %s in progress") , $engine);
2075  if ($isimage) {
2076  $filename = getParam("CORE_PUBDIR") . "/Images/workinprogress.png";
2077  } else $filename = uniqid(getTmpDir() . "/conv") . ".txt";
2078  $nc = file_put_contents($filename, $value);
2079  $vidout = 0;
2080  $err = $vf->Store($filename, false, $vidout, "", $engine, $vidin);
2081  $info = vault_properties($vidin);
2082  if (!$isimage) {
2083  unlink($filename);
2084  $mime = 'text/plain';
2085  } else {
2086  $mime = 'image/png';
2087  }
2088 
2089  $value = "$mime|$vidout";
2090  if ($err == "") $vf->rename($vidout, sprintf(_("conversion of %s in progress") . ".%s", $info->name, $engine));
2091 
2092  $this->AddComment("value $engine : $value");
2093  } else {
2094  if ($err == "") {
2095  $info1 = vault_properties($vidin);
2096  $vidout = $info->id_file;
2097  $vf->rename($vidout, sprintf(_("update of %s in progress") . ".%s", $info1->name, $engine));
2098  $value = $info->mime_s . '|' . $info->id_file;
2099  }
2100  }
2101 
2102  $err = vault_generate($this->dbaccess, $engine, $vidin, $vidout, $isimage, $this->initid);
2103  if ($err != "") {
2104  $this->addComment(sprintf(_("convert file %s as %s failed : %s") , $info->name, $engine, $err) , HISTO_ERROR);
2105  }
2106  } else {
2107  if ($isimage) {
2108  if ($info->teng_state < 0) {
2109  if ($info->teng_state == - 1) $value = "convertfail.png";
2110  else $value = "convertimpossible.png";
2111  } else {
2112  if ($info->teng_state == 1) $value = $info->mime_s . '|' . $info->id_file . '|' . $info->name;
2113  }
2114  } else {
2115  $value = $info->mime_s . '|' . $info->id_file . '|' . $info->name;
2116  }
2117  }
2118  }
2119  }
2120  return $value;
2121  }
2122  /** return all the attributes object for popup menu
2123  * the attribute can be defined in fathers
2124  * @param boolean $viewhidden set to true if need all defined menu (hidden also)
2125  * @return array DocAttribute
2126  */
2127  function GetMenuAttributes($viewhidden = false)
2128  {
2129  if (!$this->_maskApplied) $this->ApplyMask();
2130  $tsa = array();
2131 
2132  reset($this->attributes->attr);
2133  foreach ($this->attributes->attr as $k => $v) {
2134  if (((get_class($v) == "MenuAttribute")) && (($v->mvisibility != 'H') || $viewhidden)) $tsa[$v->id] = $v;
2135  }
2136  return $tsa;
2137  }
2138  /**
2139  * return all the necessary attributes
2140  * @param bool $parameters set to true if want parameters instead of attributes
2141  * @return array DocAttribute
2142  */
2143  final public function GetNeededAttributes($parameters = false)
2144  {
2145  $tsa = array();
2146 
2147  if ($parameters) {
2148  foreach ($this->attributes->attr as $k => $v) {
2149  if ((get_class($v) == "NormalAttribute") && ($v->needed) && ($v->usefor == 'Q')) $tsa[$v->id] = $v;
2150  }
2151  } else {
2152  if (!$this->_maskApplied) $this->ApplyMask();
2153  foreach ($this->attributes->attr as $k => $v) {
2154  if ((get_class($v) == "NormalAttribute") && ($v->needed) && ($v->usefor != 'Q')) $tsa[$v->id] = $v;
2155  }
2156  }
2157  return $tsa;
2158  }
2159 
2160  final public function isCompleteNeeded()
2161  {
2162  $tsa = $this->GetNeededAttributes();
2163  $err = "";
2164  foreach ($tsa as $k => $v) {
2165  if ($this->getValue($v->id) == "") $err.= sprintf(_("%s needed\n") , $v->getLabel());
2166  }
2167  return $err;
2168  }
2169 
2170  final public function equal($a, $b)
2171  {
2172  return ($this->$a == $b);
2173  }
2174  /**
2175  * return list of attribut which can be exported
2176  * @param bool $withfile true if export also file attribute
2177  * @param bool $forcedefault if true preference FREEDOM_EXPORTCOLS are not read
2178  * @return array DocAttribute
2179  */
2180  final public function GetExportAttributes($withfile = false, $forcedefault = false)
2181  {
2182  include_once ("GENERIC/generic_util.php");
2183  global $action;
2184 
2185  if ($this->doctype == 'C') $famid = $this->id;
2186  else $famid = $this->fromid;
2187  if (!$this->_maskApplied) $this->ApplyMask();
2188  $tsa = array();
2189  if (isset($this->attributes->attr)) {
2190  $pref = getFamilyParameter($action, $famid, "FREEDOM_EXPORTCOLS");
2191  if ((!$forcedefault) && ($pref != "")) {
2192 
2193  $tpref = explode(";", $pref);
2194 
2195  foreach ($this->attributes->attr as $k => $v) {
2196  if (in_array($v->id, $tpref)) {
2197  $tsa[$v->id] = $v;
2198  }
2199  }
2200  } else {
2201  foreach ($this->attributes->attr as $k => $v) {
2202  if (get_class($v) == "NormalAttribute") {
2203 
2204  if (($v->type != "array") && ($withfile || (($v->type != "image") && ($v->type != "file")))) $tsa[$v->id] = $v;
2205  }
2206  }
2207  }
2208  }
2209  return $tsa;
2210  }
2211  /**
2212  * return all the attributes object for import
2213  * @return array DocAttribute
2214  */
2215  final public function GetImportAttributes()
2216  {
2217 
2218  if (!$this->_maskApplied) $this->ApplyMask();
2219  $tsa = array();
2220  $tattr = $this->attributes->attr;
2221 
2222  foreach ($tattr as $k => $v) {
2223 
2224  if ((get_class($v) == "NormalAttribute") && (($v->mvisibility == "W") || ($v->mvisibility == "O") || ($v->type == "docid")) && ($v->type != "array")) {
2225 
2226  if (preg_match("/\(([^\)]+)\):(.+)/", $v->phpfunc, $reg)) {
2227 
2228  $aout = explode(",", $reg[2]);
2229  foreach ($aout as $ka => $va) {
2230  $ra = $this->GetAttribute($va);
2231  if ($ra) $tsa[strtolower($va) ] = $ra;
2232  }
2233  }
2234  $tsa[$v->id] = $v;
2235  }
2236  }
2237 
2238  uasort($tsa, "tordered");
2239  return $tsa;
2240  }
2241  /**
2242  * return all the attributes which can be sorted
2243  * @return array DocAttribute
2244  */
2245  public function GetSortAttributes()
2246  {
2247  $tsa = array();
2248  $nattr = $this->GetNormalAttributes();
2249  reset($nattr);
2250 
2251  foreach ($nattr as $k => $a) {
2252  if ($a->getOption('sortable') != 'yes') {
2253  if ($a->repeat || ($a->visibility == "H") || ($a->visibility == "I") || ($a->visibility == "O") || ($a->type == "longtext") || ($a->type == "xml") || (($a->type == "docid") && ($a->getOption("doctitle") == "")) || ($a->type == "htmltext") || ($a->type == "image") || ($a->type == "file") || ($a->fieldSet->visibility == "H") || ($a->getOption('sortable') == 'no')) continue;
2254  }
2255  $tsa[$a->id] = $a;
2256  }
2257  return $tsa;
2258  }
2259  // recompute the title from attribute values
2260  final public function RefreshTitle()
2261  {
2262 
2263  if ($this->doctype == 'C') return; // no refresh for family document
2264  $ltitle = $this->GetTitleAttributes();
2265 
2266  $title1 = "";
2267  foreach ($ltitle as $k => $v) {
2268  if ($this->GetValue($v->id) != "") {
2269  if ($v->type == "enum") $title1.= $this->GetHtmlValue($v, $this->GetValue($v->id)) . " ";
2270  else $title1.= $this->GetValue($v->id) . " ";
2271  }
2272  }
2273  if (chop($title1) != "") $this->title = mb_substr(chop(str_replace("\n", " ", $title1)) , 0, 255); // restric to 256 char
2274  $this->title = mb_substr(chop(str_replace("\n", " ", $this->getSpecTitle())) , 0, 255);
2275  }
2276  /**
2277  * call after construct
2278  * @return void
2279  */
2280  function postConstructor()
2281  {
2282  }
2283  /**
2284  * no in postUpdate method :: call this only if real change (values)
2285  * @return string error message
2286  */
2287  function PostModify()
2288  {
2289  // to be defined in child class
2290  return "";
2291  }
2292  /**
2293  * called when user edit a document FDL/editcard
2294  */
2295  function preEdition()
2296  {
2297  // to be defined in child class
2298  return "";
2299  }
2300  /**
2301  * called when user view a document FDL/fdl_card
2302  */
2303  function preConsultation()
2304  {
2305  // to be defined in child class
2306  return "";
2307  }
2308  /**
2309  * call in doc::postInsert method
2310  * @return string error message
2311  */
2312  function PostCreated()
2313  {
2314  // to be defined in child class
2315  return "";
2316  }
2317  /**
2318  * call in doc::add method
2319  * @return string error message
2320  */
2321  function PreCreated()
2322  {
2323  // to be defined in child class
2324  return "";
2325  }
2326  /**
2327  * call when doc is being imported before any modification
2328  * if return non null string import will ne aborted
2329  * @return string error message, if no error empty string
2330  */
2331  function preImport()
2332  {
2333  }
2334  /**
2335  * call when doc is imported after databases modification
2336  * the error message will appeared like message
2337  * @return string warning message, if no warning empty string
2338  */
2339  function postImport()
2340  {
2341  }
2342  /**
2343  * recompute values from title
2344  * the first value of type text use for title will be modify to have the new title
2345  * @param string $title new title
2346  */
2347  final public function setTitle($title)
2348  {
2349  $ltitle = $this->GetTitleAttributes();
2350  foreach ($ltitle as $at) {
2351  if (($at->type == 'text') && (($at->visibility == 'W') || ($at->visibility == 'O')) && (!$at->inArray())) {
2352  $otitle = $at;
2353  break;
2354  }
2355  }
2356  if ($otitle) {
2357  $idt = $otitle->id;
2358 
2359  $this->title = str_replace("\n", " ", $title);
2360  $this->setvalue($idt, $title);
2361  }
2362  }
2363  /**
2364  * return all attribute values
2365  *
2366  * @return array all attribute values
2367  */
2368  final public function GetValues()
2369  {
2370  $this->lvalues = array();
2371  // if (isset($this->id) && ($this->id>0)) {
2372  $nattr = $this->GetNormalAttributes();
2373  foreach ($nattr as $k => $v) {
2374  $this->lvalues[$v->id] = $this->GetValue($v->id);
2375  }
2376  // }
2377  $this->lvalues = array_merge($this->lvalues, $this->mvalues); // add more values possibilities
2378  reset($this->lvalues);
2379  return $this->lvalues;
2380  }
2381  //-------------------------------------------------------------------
2382 
2383 
2384  /**
2385  * return the value of an attribute document
2386  * @param string $idAttr identificator of attribute
2387  * @param string $def default value returned if attribute not found or if is empty
2388  * @return string the attribute value
2389  */
2390  final public function getValue($idAttr, $def = "")
2391  {
2392 
2393  $lidAttr = strtolower($idAttr);
2394  if (isset($this->$lidAttr) && ($this->$lidAttr != "")) return $this->$lidAttr;
2395 
2396  return $def;
2397  }
2398  /**
2399  * return the value of an list attribute document
2400  *
2401  * the attribute must be in an array or of a type '*list' like enumlist or textlist
2402  * @param string $idAttr identificator of list attribute
2403  * @param string $def default value returned if attribute not found or if is empty
2404  * @param string $index the values for $index row (default value -1 means all values)
2405  * @return array the list of attribute values
2406  */
2407  final public function getTValue($idAttr, $def = "", $index = - 1)
2408  {
2409  $v = $this->getValue("$idAttr", $def);
2410  if ($v == "") {
2411  if ($index == - 1) return array();
2412  else return $def;
2413  } else if ($v == "\t") {
2414  if ($index == - 1) return array(
2415  ""
2416  );
2417  else return "";
2418  }
2419  $t = $this->_val2array($v);
2420  if ($index == - 1) {
2421  $oa = $this->getAttribute($idAttr);
2422  if ($oa && $oa->type == "xml") {
2423  foreach ($t as $k => $v) {
2424  $t[$k] = str_replace('<BR>', "\n", $v);
2425  }
2426  }
2427  return $t;
2428  }
2429  if (isset($t[$index])) {
2430  $oa = $this->getAttribute($idAttr);
2431  if ($oa && $oa->type == "xml") $t[$index] = str_replace('<BR>', "\n", $t[$index]);
2432  return $t[$index];
2433  } else return $def;
2434  }
2435  /**
2436  * return the array of values for an array attribute
2437  *
2438  * the attribute must an array type
2439  * @param string $idAttr identificator of array attribute
2440  * @param string $index the values for $index row (default value -1 means all values)
2441  * @return array all values of array order by rows (return false if not an array attribute)
2442  */
2443  final public function getAValues($idAttr, $index = - 1)
2444  {
2445  $a = $this->getAttribute($idAttr);
2446  if ($a->type == "array") {
2447  $ta = $this->attributes->getArrayElements($a->id);
2448  $ti = array();
2449  // transpose
2450  foreach ($ta as $k => $v) {
2451  $tv[$k] = $this->getTValue($k);
2452  $ix = max($ix, count($tv[$k]));
2453  }
2454  for ($i = 0; $i < $ix; $i++) {
2455  $ti[$i] = array();
2456  }
2457  foreach ($ta as $k => $v) {
2458  for ($i = 0; $i < $ix; $i++) {
2459  $ti[$i]+= array(
2460  $k => $tv[$k][$i]
2461  );
2462  }
2463  }
2464  if ($index == - 1) return $ti;
2465  else return $ti[$index];
2466  }
2467  return false;
2468  }
2469  /**
2470  * delete a row in an array attribute
2471  *
2472  * the attribute must an array type
2473  * @param string $idAttr identificator of array attribute
2474  * @param string $index $index row (first is 0)
2475  * @return string error message, if no error empty string
2476  */
2477  final public function removeArrayRow($idAttr, $index)
2478  {
2479  $a = $this->getAttribute($idAttr);
2480  if ($a->type == "array") {
2481  $ta = $this->attributes->getArrayElements($a->id);
2482  $ti = array();
2483  $err = "";
2484  // delete in each columns
2485  foreach ($ta as $k => $v) {
2486  $tv = $this->getTValue($k);
2487  unset($tv[$index]);
2488  $tvu = array();
2489  foreach ($tv as $vv) $tvu[] = $vv; // key reorder
2490  $err.= $this->setValue($k, $tvu);
2491  }
2492  return $err;
2493  }
2494  return sprintf(_("%s is not an array attribute") , $idAttr);
2495  }
2496  /**
2497  * in case of array where each column are not the same length
2498  *
2499  * the attribute must an array type
2500  * fill uncomplete column with null values
2501  * @param string $idAttr identificator of array attribute
2502  * @return string error message, if no error empty string
2503  */
2504  final public function completeArrayRow($idAttr)
2505  {
2506  $a = $this->getAttribute($idAttr);
2507  if ($a->type == "array") {
2508  $ta = $this->attributes->getArrayElements($a->id);
2509 
2510  $max = - 1;
2511  $maxdiff = false;
2512  foreach ($ta as $k => $v) { // detect uncompleted rows
2513  $c = count($this->getTValue($k));
2514  if ($max < 0) $max = $c;
2515  else {
2516  if ($c != $max) $maxdiff = true;
2517  if ($max < $c) $max = $c;
2518  }
2519  }
2520  if ($maxdiff) {
2521  foreach ($ta as $k => $v) { // fill uncompleted rows
2522  $c = count($this->getTValue($k));
2523  if ($c < $max) {
2524  $t = $this->getTValue($k);
2525  $t = array_pad($t, $max, "");
2526  $err.= $this->setValue($k, $t);
2527  }
2528  }
2529  }
2530 
2531  return $err;
2532  }
2533  return sprintf(_("%s is not an array attribute") , $idAttr);
2534  }
2535  /**
2536  * add new row in an array attribute
2537  *
2538  * the attribute must be an array type
2539  * @param string $idAttr identificator of array attribute
2540  * @param array $tv values of each column. Array index must be the attribute identificator
2541  * @param string $index $index row (first is 0) -1 at the end; x means before x row
2542  * @return string error message, if no error empty string
2543  */
2544  final public function addArrayRow($idAttr, $tv, $index = - 1)
2545  {
2546  $a = $this->getAttribute($idAttr);
2547  if ($a->type == "array") {
2548  $err = $this->completeArrayRow($idAttr);
2549  if ($err == "") {
2550  $ta = $this->attributes->getArrayElements($a->id);
2551  $ti = array();
2552  $err = "";
2553  // add in each columns
2554  foreach ($ta as $k => $v) {
2555  $tnv = $this->getTValue($k);
2556  $val = $tv[strtolower($k) ];
2557  if ($index == 0) {
2558  array_unshift($tnv, $val);
2559  } elseif ($index > 0 && $index < count($tnv)) {
2560  $t1 = array_slice($tnv, 0, $index);
2561  $t2 = array_slice($tnv, $index);
2562  $tnv = array_merge($t1, array(
2563  $val
2564  ) , $t2);
2565  } else {
2566  $tnv[] = $val;
2567  }
2568  $err.= $this->setValue($k, $tnv);
2569  }
2570  if ($err = "") {
2571  $err = $this->completeArrayRow($idAttr);
2572  }
2573  }
2574  return $err;
2575  }
2576  return sprintf(_("%s is not an array attribute") , $idAttr);
2577  }
2578  /**
2579  * affect value for $attrid attribute
2580  *
2581  * the affectation is only in object. To set modification in database the modify method must be
2582  * call after modification
2583  * If value is empty no modification are set. To reset a value use Doc::DeleteValue method.
2584  * an array can be use as value for values which are in arrays
2585  * @param string $idAttr identificator of attribute
2586  * @param string $value new value for the attribute
2587  * @param int $index only for array values affect value in a specific row
2588  * @param int &$kvalue in case of error the index of error (for arrays)
2589  * @return string error message, if no error empty string
2590  */
2591  final public function SetValue($attrid, $value, $index = - 1, &$kvalue = null)
2592  {
2593  // control edit before set values
2594  if (!$this->withoutControl) {
2595  if ($this->id > 0) { // no control yet if no effective doc
2596  $err = $this->Control("edit");
2597  if ($err != "") return ($err);
2598  }
2599  }
2600  $attrid = strtolower($attrid);
2601  $oattr = $this->GetAttribute($attrid);
2602  if ($index > - 1) { // modify one value in a row
2603  $tval = $this->getTValue($attrid);
2604  $tval[$index] = $value;
2605  $value = $tval;
2606  }
2607  if (is_array($value)) {
2608  if ($oattr->type == 'htmltext') {
2609  $value = $this->_array2val($value, "\r");
2610  if ($value === '') {
2611  $value = DELVALUE;
2612  }
2613  } else {
2614  if (count($value) == 0) {
2615  $value = DELVALUE;
2616  } elseif ((count($value) == 1) && (first($value) === "" || first($value) === " " || first($value) === null) && (substr(key($value) , 0, 1) != "s")) {
2617  $value = "\t"; // special tab for array of one empty cell
2618 
2619  } else {
2620  if ($oattr->repeat && (count($value) == 1) && substr(key($value) , 0, 1) == "s") {
2621  $ov = $this->getTValue($attrid);
2622  $rank = intval(substr(key($value) , 1));
2623  if (count($ov) < ($rank - 1)) { // fill array if not set
2624  $start = count($ov);
2625  for ($i = $start; $i < $rank; $i++) $ov[$i] = "";
2626  }
2627  foreach ($value as $k => $v) $ov[substr($k, 1, 1) ] = $v;
2628  $value = $this->_array2val($ov);
2629  } else {
2630  $value = $this->_array2val($value);
2631  }
2632  }
2633  }
2634  }
2635  if (($value !== "") && ($value !== null)) {
2636  // change only if different
2637  if ($oattr === false) return sprintf(_("attribute %s unknow in family %s [%d]") , $attrid, $this->title, $this->id);
2638  if ($oattr->mvisibility == "I") return sprintf(_("no permission to modify this attribute %s") , $attrid);
2639  if ($value === DELVALUE) {
2640  if ($oattr->type != "password") $value = " ";
2641  else return;
2642  }
2643  if ($value === " ") {
2644  $value = ""; // erase value
2645  if ($this->$attrid != "") {
2646  $this->hasChanged = true;
2647  //print "change by delete $attrid <BR>";
2648  $this->_oldvalue[$attrid] = $this->$attrid;
2649  $this->$attrid = "";
2650  if ($oattr->type == "file") {
2651  // need clear computed column
2652  $this->clearFullAttr($oattr->id);
2653  }
2654  }
2655  } else {
2656  $value = trim($value, " \x0B\r"); // suppress white spaces end & begin
2657  if (!isset($this->$attrid)) $this->$attrid = "";
2658 
2659  if (strcmp($this->$attrid, $value) != 0 && strcmp($this->$attrid, str_replace("\n ", "\n", $value)) != 0) {
2660  $this->hasChanged = true;
2661  // print "change2 $attrid to <PRE>[{$this->$attrid}] [$value]</PRE><BR>";
2662  if ($oattr->repeat) {
2663  $tvalues = $this->_val2array($value);
2664  } else {
2665  $tvalues[] = $value;
2666  }
2667 
2668  foreach ($tvalues as $kvalue => $avalue) {
2669  if (($avalue != "") && ($avalue != "\t")) {
2670  if ($oattr) {
2671  $avalue = trim($avalue);
2672  $tvalues[$kvalue] = $avalue;
2673  switch ($oattr->type) {
2674  case 'docid':
2675  if ((!strstr($avalue, "<BR>")) && (!strstr($avalue, "\n")) && (!is_numeric($avalue))) {
2676  $tvalues[$kvalue] = getIdFromName($this->dbaccess, $avalue);
2677  }
2678  break;
2679 
2680  case 'enum':
2681  if ($oattr->getOption("etype") == "open") {
2682  // added new
2683  $tenum = $oattr->getEnum();
2684  $keys = array_keys($tenum);
2685  if (!in_array($avalue, $keys)) {
2686  $oattr->addEnum($this->dbaccess, $avalue, $avalue);
2687  }
2688  }
2689  break;
2690 
2691  case 'double':
2692  if ($avalue == '-') $avalue = 0;
2693  $tvalues[$kvalue] = str_replace(",", ".", $avalue);
2694  $tvalues[$kvalue] = str_replace(" ", "", $tvalues[$kvalue]);
2695  if (($avalue != "\t") && (!is_numeric($tvalues[$kvalue]))) return sprintf(_("value [%s] is not a number") , $tvalues[$kvalue]);
2696  break;
2697 
2698  case 'money':
2699  if ($avalue == '-') $avalue = 0;
2700  $tvalues[$kvalue] = str_replace(",", ".", $avalue);
2701  $tvalues[$kvalue] = str_replace(" ", "", $tvalues[$kvalue]);
2702  if (($avalue != "\t") && (!is_numeric($tvalues[$kvalue]))) return sprintf(_("value [%s] is not a number") , $tvalues[$kvalue]);
2703  $tvalues[$kvalue] = round(doubleval($tvalues[$kvalue]) , 2);
2704  break;
2705 
2706  case 'integer':
2707  case 'int':
2708  if ($avalue == '-') $avalue = 0;
2709  if (($avalue != "\t") && (!is_numeric($avalue))) return sprintf(_("value [%s] is not a number") , $avalue);
2710  if (intval($avalue) != floatval($avalue)) return sprintf(_("[%s] must be a integer") , $avalue);
2711 
2712  $tvalues[$kvalue] = intval($avalue);
2713  break;
2714 
2715  case 'time':
2716  $tt = explode(":", $avalue);
2717  if (count($tt) == 2) {
2718  list($hh, $mm) = $tt;
2719  $tvalues[$kvalue] = sprintf("%02d:%02d", intval($hh) % 24, intval($mm) % 60);
2720  } else if (count($tt) == 3) {
2721  list($hh, $mm, $ss) = $tt;
2722  $tvalues[$kvalue] = sprintf("%02d:%02d:%02d", intval($hh) % 24, intval($mm) % 60, intval($ss) % 60);
2723  }
2724  break;
2725 
2726  case 'date':
2727  if (trim($avalue) == "") {
2728  if (!$oattr->repeat) $tvalues[$kvalue] = "";
2729  } else {
2730 
2731  $localeconfig = getLocaleConfig();
2732  if ($localeconfig !== false) {
2733  $tvalues[$kvalue] = stringDateToIso($avalue, $localeconfig['dateFormat']);
2734  if (getLcdate() != "iso") $tvalues[$kvalue] = preg_replace('#^([0-9]{4})-([0-9]{2})-([0-9]{2})#', '$3/$2/$1', $tvalues[$kvalue]);
2735  } else {
2736  return sprintf(_("value [%s] is not a valid date") , $avalue);
2737  }
2738  }
2739  break;
2740 
2741  case 'timestamp':
2742  if (trim($avalue) == "") {
2743  if (!$oattr->repeat) $tvalues[$kvalue] = "";
2744  } else {
2745  $localeconfig = getLocaleConfig();
2746  if ($localeconfig !== false) {
2747  $tvalues[$kvalue] = stringDateToIso($avalue, $localeconfig['dateTimeFormat']);
2748  if (getLcdate() != "iso") $tvalues[$kvalue] = preg_replace('#^([0-9]{4})-([0-9]{2})-([0-9]{2})#', '$3/$2/$1', $tvalues[$kvalue]);
2749  } else {
2750  return sprintf(_("value [%s] is not a valid timestamp") , $avalue);
2751  }
2752  }
2753  break;
2754 
2755  case 'file':
2756  // clear fulltext realtive column
2757  if ((!$oattr->repeat) || ($avalue != $this->getTValue($attrid, "", $kvalue))) {
2758  // only if changed
2759  $this->clearFullAttr($oattr->id, ($oattr->repeat) ? $kvalue : -1);
2760  }
2761  $tvalues[$kvalue] = str_replace('\\', '', $tvalues[$kvalue]); // correct possible save error in old versions
2762  break;
2763 
2764  case 'image':
2765  $tvalues[$kvalue] = str_replace('\\', '', $tvalues[$kvalue]);
2766  break;
2767 
2768  case 'htmltext':
2769  $tvalues[$kvalue] = preg_replace("/<!--.*?-->/ms", "", $tvalues[$kvalue]); //delete comments
2770  /* Double encode the entities we want to keep encoded as entities
2771  * after the html_entity_decode() below.
2772  */
2773  $tvalues[$kvalue] = preg_replace('/&(gt|lt|amp|quot|apos);/', '&amp;\1;', $tvalues[$kvalue]);
2774  //delete fake fck editor id set in IE8
2775  $tvalues[$kvalue] = preg_replace('/(<span\s+id="[0-9]+S"\s+style="display:\s*none">&nbsp;<\/span>)/u','', $tvalues[$kvalue]);
2776  $tvalues[$kvalue] = preg_replace('/(<span)(\s+id="[0-9]+S"\s+style="display:\s*none")(.*)/u','\1\3', $tvalues[$kvalue]);
2777 
2778  $tvalues[$kvalue] = str_replace(array(
2779  '<noscript',
2780  '</noscript>',
2781  '<script',
2782  '</script>'
2783  ) , array(
2784  '<pre',
2785  '</pre>',
2786  '<pre',
2787  '</pre>'
2788  ) , html_entity_decode($tvalues[$kvalue], ENT_NOQUOTES, 'UTF-8'));
2789  $tvalues[$kvalue] = str_replace("[", "&#x5B;", $tvalues[$kvalue]); // need to stop auto instance
2790  $tvalues[$kvalue] = str_replace('--quoteric--', '&amp;quot;', $tvalues[$kvalue]); // reinject original quote entity
2791  $tvalues[$kvalue] = preg_replace("/<\/?meta[^>]*>/s", "", $tvalues[$kvalue]);
2792  if ($oattr->getOption("htmlclean") == "yes") {
2793  $tvalues[$kvalue] = preg_replace("/<\/?span[^>]*>/s", "", $tvalues[$kvalue]);
2794  $tvalues[$kvalue] = preg_replace("/<\/?font[^>]*>/s", "", $tvalues[$kvalue]);
2795  $tvalues[$kvalue] = preg_replace("/<style[^>]*>.*?<\/style>/s", "", $tvalues[$kvalue]);
2796  $tvalues[$kvalue] = preg_replace("/<([^>]*) style=\"[^\"]*\"/s", "<\\1", $tvalues[$kvalue]);
2797  $tvalues[$kvalue] = preg_replace("/<([^>]*) class=\"[^\"]*\"/s", "<\\1", $tvalues[$kvalue]);
2798  }
2799  break;
2800 
2801  case 'thesaurus':
2802  // reset cache of doccount
2803  include_once ("FDL/Class.DocCount.php");
2804  $d = new docCount($this->dbaccess);
2805  $d->famid = $this->fromid;
2806  $d->aid = $attrid;
2807  $d->deleteAll();
2808  break;
2809 
2810  case 'text':
2811  $tvalues[$kvalue] = str_replace("\r", " ", $tvalues[$kvalue]);
2812  break;
2813  }
2814  }
2815  }
2816  }
2817  //print "<br/>change $attrid to :".$this->$attrid."->".implode("\n",$tvalues);
2818  $this->_oldvalue[$attrid] = $this->$attrid;
2819  $this->$attrid = implode("\n", $tvalues);
2820  }
2821  }
2822  }
2823  }
2824  /**
2825  * clear $attrid_txt and $attrid_vec
2826  *
2827  * @param string $idAttr identificator of file attribute
2828  * @return string error message, if no error empty string
2829  */
2830  final private function clearFullAttr($attrid, $index = - 1)
2831  {
2832  $attrid = strtolower($attrid);
2833  $oa = $this->getAttribute($attrid);
2834  if ($oa && $oa->usefor != 'Q') {
2835  if ($oa->getOption("search") != "no") {
2836  $ak = $attrid . '_txt';
2837  if ($index == - 1) {
2838  $this->$ak = '';
2839  } else {
2840  if ($this->AffectColumn(array(
2841  $ak
2842  ))) {
2843  $this->$ak = sep_replace($this->$ak, $index);
2844  }
2845  }
2846  $this->fields[$ak] = $ak;
2847  $ak = $attrid . '_vec';
2848  $this->$ak = '';
2849  $this->fields[$ak] = $ak;
2850  $this->fulltext = '';
2851  $this->fields['fulltext'] = 'fulltext'; // to enable trigger
2852  $this->textsend[$attrid . $index] = array(
2853  "attrid" => $attrid,
2854  "index" => $index
2855  );
2856  }
2857  }
2858  }
2859  /**
2860  * send text transformation
2861  * after ::clearFullAttr is called
2862  *
2863  */
2864  final private function sendTextToEngine()
2865  {
2866  if (is_array($this->textsend)) {
2867  include_once ("FDL/Lib.Vault.php");
2868  foreach ($this->textsend as $k => $v) {
2869  $index = $v["index"];
2870  if ($index > 0) $fval = $this->getTValue($v["attrid"], "", $index);
2871  else $fval = strtok($this->getValue($v["attrid"]) , "\n");
2872  if (preg_match(PREGEXPFILE, $fval, $reg)) {
2873  $vid = $reg[2];
2874  $err = sendTextTransformation($this->dbaccess, $this->id, $v["attrid"], $index, $vid);
2875  if ($err != "") $this->AddComment(_("error sending text conversion") . ": $err", HISTO_NOTICE);
2876  }
2877  }
2878  $this->textsend = array(); //reinit
2879 
2880  }
2881  }
2882  /**
2883  * force recompute all file text transformation
2884  * @param string $aid file attribute identificator. If false all files attributes will be reseted
2885  * @return string error message, if no error empty string
2886  */
2887  final public function recomputeTextFiles($aid = false)
2888  {
2889  if (!$aid) $afiles = $this->GetFileAttributes(true);
2890  else $afiles[$aid] = $this->getAttribute($aid);
2891 
2892  $ttxt = array();
2893  foreach ($afiles as $k => $v) {
2894  $kt = $k . '_txt';
2895  $ttxt[] = $kt;
2896  if ($v->inArray()) {
2897  $tv = $this->getTValue($k);
2898  foreach ($tv as $kv => $vv) {
2899  $this->clearFullAttr($k, $kv);
2900  }
2901  } else {
2902  $this->clearFullAttr($k);
2903  }
2904  $this->$kt = '';
2905  $kv = $k . '_vec';
2906  $ttxt[] = $kv;
2907  $this->$kv = '';
2908  }
2909  $this->modify(true, $ttxt, true);
2910  $err = $this->sendTextToEngine();
2911  return $err;
2912  }
2913  /**
2914  * affect text value in $attrid file attribute
2915  *
2916  * create a new file in Vault to replace old file
2917  * @param string $idAttr identificator of file attribute
2918  * @param string $value new value for the attribute
2919  * @param string $ftitle the name of file (if empty the same as before)
2920  * @return string error message, if no error empty string
2921  */
2922  final public function SetTextValueInFile($attrid, $value, $ftitle = "")
2923  {
2924  $a = $this->getAttribute($attrid);
2925  if ($a->type == "file") {
2926  $err = "file conversion";
2927  $vf = newFreeVaultFile($this->dbaccess);
2928  $fvalue = $this->getValue($attrid);
2929  $basename = "";
2930  if (preg_match(PREGEXPFILE, $fvalue, $reg)) {
2931  $vaultid = $reg[2];
2932  $mimetype = $reg[1];
2933 
2934  $err = $vf->Retrieve($vaultid, $info);
2935 
2936  if ($err == "") {
2937  $basename = $info->name;
2938  }
2939  }
2940  $filename = uniqid(getTmpDir() . "/_html") . ".html";
2941  $nc = file_put_contents($filename, $value);
2942  $err = $vf->Store($filename, false, $vid);
2943  if ($ftitle != "") {
2944  $vf->Rename($vid, $ftitle);
2945  $basename = $ftitle;
2946  } else {
2947  if ($basename != "") { // keep same file name
2948  $vf->Rename($vid, $basename);
2949  }
2950  }
2951  if ($err == "") {
2952  $mime = trim(shell_exec(sprintf("file -ib %s", escapeshellarg($filename))));
2953  $value = "$mime|$vid|$basename";
2954  $err = $this->setValue($attrid, $value);
2955  //$err="file conversion $mime|$vid";
2956  if ($err == "xx") {
2957  $index = 0;
2958  $this->clearFullAttr($attrid); // because internal values not changed
2959 
2960  }
2961  }
2962  if ($nc > 0) unlink($filename);
2963  }
2964  return $err;
2965  }
2966  /**
2967  * get text value from $attrid file attribute
2968  *
2969  * get content of a file (must be an ascii file)
2970  * @param string $idAttr identificator of file attribute
2971  * @param string &$text the content of the file
2972  * @return string error message, if no error empty string
2973  */
2974  final public function getTextValueFromFile($attrid, &$text)
2975  {
2976  $a = $this->getAttribute($attrid);
2977  if ($a->type == "file") {
2978  $vf = newFreeVaultFile($this->dbaccess);
2979  $fvalue = $this->getValue($attrid);
2980  $basename = "";
2981  if (preg_match(PREGEXPFILE, $fvalue, $reg)) {
2982  $vaultid = $reg[2];
2983  $mimetype = $reg[1];
2984 
2985  $err = $vf->Retrieve($vaultid, $info);
2986 
2987  if ($err == "") {
2988  $basename = $info->name;
2989  }
2990  }
2991  $filename = $info->path;
2992  $text = file_get_contents($filename);
2993  }
2994  return $err;
2995  }
2996  /**
2997  * save stream file in an file attribute
2998  *
2999  * replace a new file in Vault to replace old file
3000  * @param string $idAttr identificator of file attribute
3001  * @param stream $stream file resource from fopen
3002  * @param int $index for array of file : modify in specific row
3003  * @return string error message, if no error empty string
3004  */
3005  final public function saveFile($attrid, $stream, $ftitle = "", $index = - 1)
3006  {
3007  if (is_resource($stream) && get_resource_type($stream) == "stream") {
3008 
3009  $a = $this->getAttribute($attrid);
3010  if ($a->type == "file") {
3011  $err = "file conversion";
3012  $vf = newFreeVaultFile($this->dbaccess);
3013  if ($index > - 1) $fvalue = $this->getTValue($attrid, '', $index);
3014  else $fvalue = $this->getValue($attrid);
3015  $basename = "";
3016  if (preg_match(PREGEXPFILE, $fvalue, $reg)) {
3017  $vaultid = $reg[2];
3018  $mimetype = $reg[1];
3019  $oftitle = $reg[3];
3020  $err = $vf->Retrieve($vaultid, $info);
3021 
3022  if ($err == "") {
3023  $basename = $info->name;
3024  }
3025  }
3026  if ($ftitle) {
3027  $ext = getFileExtension($ftitle);
3028  }
3029  if ($ext == "") $ext = "nop";
3030 
3031  $filename = uniqid(getTmpDir() . "/_fdl") . ".$ext";
3032  $tmpstream = fopen($filename, "w");
3033  while (!feof($stream)) {
3034  if (false === fwrite($tmpstream, fread($stream, 4096))) {
3035  $err = "403 Forbidden";
3036  break;
3037  }
3038  }
3039  fclose($tmpstream);
3040  // verify if need to create new file in case of revision
3041  $newfile = ($basename == "");
3042 
3043  if ($this->revision > 0) {
3044  $trev = $this->GetRevisions("TABLE", 2);
3045  $revdoc = $trev[1];
3046  $prevfile = getv($revdoc, strtolower($attrid));
3047  if ($prevfile == $fvalue) $newfile = true;
3048  }
3049 
3050  if (!$newfile) {
3051  $err = $vf->Save($filename, false, $vaultid);
3052  } else {
3053  $err = $vf->Store($filename, false, $vaultid);
3054  }
3055  if ($ftitle != "") {
3056  $vf->Rename($vaultid, $ftitle);
3057  } elseif ($basename != "") { // keep same file name
3058  $vf->Rename($vaultid, $basename);
3059  }
3060  if ($err == "") {
3061  if ($mimetype) $mime = $mimetype;
3062  else $mime = trim(shell_exec(sprintf("file -ib %s", escapeshellarg($filename))));
3063  if ($ftitle) $value = "$mime|$vaultid|$ftitle";
3064  else $value = "$mime|$vaultid|$oftitle";
3065  $err = $this->setValue($attrid, $value, $index);
3066  if ($err == "") {
3067  $index = 0;
3068  $this->clearFullAttr($attrid); // because internal values not changed
3069 
3070  }
3071  //$err="file conversion $mime|$vid";
3072 
3073  }
3074  unlink($filename);
3075  $this->AddComment(sprintf(_("modify file %s") , $ftitle));
3076  $this->hasChanged = true;
3077  }
3078  }
3079  return $err;
3080  }
3081  /**
3082  * use for duplicate physicaly the file
3083  *
3084  * @param string $idattr identificator of file attribute
3085  * @param string $newname basename if want change name of file
3086  * @param int $index in case of array
3087  * @return string attribut value formated to be inserted into a file attribute
3088  */
3089  final function copyFile($idattr, $newname = "", $index = - 1)
3090  {
3091  if ($index >= 0) $f = $this->getTValue($idattr, "", $index);
3092  else $f = $this->getValue($idattr);
3093  if ($f) {
3094  if (preg_match(PREGEXPFILE, $f, $reg)) {
3095  $vf = newFreeVaultFile($this->dbaccess);
3096  if ($vf->Show($reg[2], $info) == "") {
3097  $cible = $info->path;
3098  if (file_exists($cible)) {
3099  $err = $vf->Store($cible, false, $vid);
3100  if ($err == "") {
3101  if (!$newname) $newname = $info->name;
3102  if ($newname) {
3103  $vf->Rename($vid, $newname);
3104  }
3105  return $reg[1] . "|$vid|$newname";
3106  }
3107  }
3108  }
3109  }
3110  }
3111  return false;
3112  }
3113  /**
3114  * rename physicaly the file
3115  *
3116  * @param string $idattr identificator of file attribute
3117  * @param string $newname base name file
3118  * @param int $index in case of array of files
3119  * @return string empty if no error
3120  */
3121  final function renameFile($idattr, $newname, $index = - 1)
3122  {
3123  if ($newname) {
3124  if ($index == - 1) $f = $this->getValue($idattr);
3125  else $f = $this->getTValue($idattr, "", $index);
3126  if ($f) {
3127  if (preg_match(PREGEXPFILE, $f, $reg)) {
3128  $vf = newFreeVaultFile($this->dbaccess);
3129  $vid = $reg[2];
3130  if ($vf->Show($reg[2], $info) == "") {
3131  $cible = $info->path;
3132  if (file_exists($cible)) {
3133  if ($err == "") {
3134  $vf->Rename($vid, $newname);
3135  $this->setValue($idattr, $info->mime_s . '|' . $vid . '|' . $newname, $index);
3136  }
3137  }
3138  }
3139  }
3140  }
3141  }
3142  return false;
3143  }
3144  /**
3145  * store new file in an file attribute
3146  *
3147  * @param string $idAttr identificator of file attribute
3148  * @param string $filename file path
3149  * @param string $ftitle basename of file
3150  * @param int $index only for array values affect value in a specific row
3151  * @return string error message, if no error empty string
3152  */
3153  final public function storeFile($attrid, $filename, $ftitle = "", $index = - 1)
3154  {
3155  if (is_file($filename)) {
3156  include_once ("FDL/Lib.Vault.php");
3157 
3158  $a = $this->getAttribute($attrid);
3159  if ($a) {
3160  if (($a->type == "file") || ($a->type == "image")) {
3161  $err = vault_store($filename, $vaultid, $ftitle);
3162  if ($err == "") {
3163  $info = vault_properties($vaultid);
3164  $mime = $info->mime_s;
3165  if (!$ftitle) $ftitle = $info->name;
3166  $this->setValue($attrid, "$mime|$vaultid|$ftitle", $index);
3167  }
3168  } else {
3169  $err = sprintf(_("attribute %s is not a file attribute") , $a->getLabel());
3170  }
3171  } else {
3172  $err = sprintf(_("unknow attribute %s") , $attrid);
3173  }
3174  }
3175  return $err;
3176  }
3177  /**
3178  * store multiples new files in an file array attribute
3179  *
3180  * @param string $idAttr identificator of file attribute
3181  * @param array $filename file path
3182  * @param array $ftitle basename of file
3183  * @return string error message, if no error empty string
3184  */
3185  final public function storeFiles($attrid, $filenames, $ftitle = "")
3186  {
3187  if (!is_array($filenames)) return _("no files");
3188 
3189  $a = $this->getAttribute($attrid);
3190  if (($a->type == "file") || ($a->type == "image")) {
3191  if ($a->inArray()) {
3192  $tvid = array();
3193  foreach ($filenames as $k => $filename) {
3194  if (is_file($filename)) {
3195  include_once ("FDL/Lib.Vault.php");
3196 
3197  $err = vault_store($filename, $vaultid, $ftitle[$k]);
3198  if ($err == "") {
3199  $info = vault_properties($vaultid);
3200  $mime = $info->mime_s;
3201  if ($ftitle[$k] == "") $ftitle[$k] = $info->name;
3202  $tvid[] = "$mime|$vaultid|" . $ftitle[$k];
3203  }
3204  }
3205  }
3206  $this->setValue($attrid, $tvid);
3207  } else {
3208  $err = sprintf(_("attribute %s is not int a array") , $a->getLabel());
3209  }
3210  } else {
3211  $err = sprintf(_("attribute %s is not a file attribute") , $a->getLabel());
3212  }
3213 
3214  return $err;
3215  }
3216  /**
3217  * Duplicate physically all files of documents
3218  *
3219  */
3220  function duplicateFiles()
3221  {
3222  $err = "";
3223  $fa = $this->GetFileAttributes();
3224  foreach ($fa as $aid => $oa) {
3225  if ($oa->inArray()) {
3226  $t = $this->getTvalue($oa->id);
3227  $tcopy = array();
3228  foreach ($t as $k => $v) {
3229  $tcopy[$k] = $this->copyFile($oa->id, "", $k);
3230  }
3231  $this->setValue($oa->id, $tcopy);
3232  } else {
3233  $this->setValue($oa->id, $this->copyFile($oa->id));
3234  }
3235  }
3236  return $err;
3237  }
3238  /**
3239  * return the related value by linked attributes
3240  * @param string $RidAttr attribute identificator
3241  * @param string def $def default return value
3242  * @param bool $latest always last revision of document
3243  */
3244  final public function GetRValue($RidAttr, $def = "", $latest = true, $html = false)
3245  {
3246  $tattrid = explode(":", $RidAttr);
3247  $lattrid = array_pop($tattrid); // last attribute
3248  $doc = $this;
3249  foreach ($tattrid as $k => $v) {
3250  $docid = $doc->getValue($v);
3251  if ($docid == "") return $def;
3252  $doc = new_Doc($this->dbaccess, $docid);
3253 
3254  if ($latest) {
3255  if ($doc->locked == - 1) { // it is revised document
3256  $ldocid = $doc->latestId();
3257  if ($ldocid != $doc->id) $doc = new_Doc($this->dbaccess, $ldocid);
3258  }
3259  }
3260  if (!$doc->isAlive()) return $def;
3261  }
3262  if ($html) return $doc->getHtmlAttrValue($lattrid, $def);
3263  else return $doc->getValue($lattrid, $def);
3264  }
3265  /**
3266  * return the previous value for a attibute set before Doc::SetValue
3267  * can be use in Doc::postModify generaly
3268  * @param string $attrid identificator of attribute
3269  * @return string the old value (false if not modified before)
3270  *
3271  */
3272  final public function getOldValue($attrid)
3273  {
3274  $attrid = strtolower($attrid);
3275  if (isset($this->_oldvalue[$attrid])) return $this->_oldvalue[$attrid];
3276  return false;
3277  }
3278  final public function getOldValues()
3279  {
3280  if (isset($this->_oldvalue)) return $this->_oldvalue;
3281  return array();
3282  }
3283 
3284  final public function DeleteValue($attrid)
3285  {
3286  $oattr = $this->GetAttribute($attrid);
3287  if ($oattr->type == 'docid') {
3288  $doctitle = $oattr->getOption('doctitle');
3289  if ($doctitle == 'auto') {
3290  $doctitle = $attrid . '_title';
3291  }
3292  if (!empty($doctitle)) {
3293  $this->SetValue($doctitle, " ");
3294  }
3295  }
3296  return $this->SetValue($attrid, " ");
3297  }
3298  /**
3299  * add values present in values field
3300  */
3301  private function GetMoreValues()
3302  {
3303  if (isset($this->values)) {
3304  $tvalues = explode("£", $this->values);
3305  $tattrids = explode("£", $this->attrids);
3306 
3307  foreach ($tvalues as $k => $v) {
3308  $attrid = $tattrids[$k];
3309  if (($attrid != "") && ($this->$attrid == "")) {
3310  $this->$attrid = $v;
3311  $this->mvalues[$attrid] = $v; // to be use in getValues()
3312 
3313  }
3314  }
3315  }
3316  }
3317  /**
3318  * reset values present in values field
3319  */
3320  private function ResetMoreValues()
3321  {
3322  if (isset($this->values) && $this->id) {
3323  $tattrids = explode("£", $this->attrids);
3324 
3325  foreach ($tattrids as $k => $v) {
3326  $attrid = $tattrids[$k];
3327  if ($attrid) $this->$attrid = "";
3328  }
3329  }
3330  $this->mvalues = array();
3331  }
3332 
3333  final public function GetValueMethod($value, $attrid = '')
3334  {
3335 
3336  $value = $this->ApplyMethod($value, $value);
3337 
3338  return $value;
3339  }
3340  /**
3341  * apply a method to a doc
3342  * specified like ::getFoo(10)
3343  * @param string $method the method to apply
3344  * @param string $def default value if no method
3345  * @param int $index index in case of value in row
3346  * @param array $bargs first arguments sent before for the method
3347  * @param array $mapArgs indexed array to add more possibilities to map arguments
3348  * @param string $err error message
3349  *
3350  * @return string the value
3351  */
3352  final public function applyMethod($method, $def = "", $index = - 1, array $bargs = array() , array $mapArgs = array() , &$err = '')
3353  {
3354  $value = $def;
3355  $err = '';
3356  if (preg_match('/([^:]*)::([^\(]+)\(([^\)]*)\)/', $method, $reg)) {
3357  $staticClass = $reg[1];
3358  if (!$staticClass) $staticClass = $this;
3359  $methodName = $reg[2];
3360  $returnArgs = $reg[3];
3361  if (method_exists($staticClass, $methodName)) {
3362  if (($returnArgs == "") && (empty($bargs))) {
3363  // without argument
3364  $value = call_user_func(array(
3365  $staticClass,
3366  $methodName
3367  ));
3368  } else {
3369  // with argument
3370  //$args = explode(",", $reg[2]);
3371  $sargs = $returnArgs;
3372  $args = array();
3373  $ak = 0;
3374  $bq = '';
3375  for ($i = 0; $i < strlen($sargs); $i++) {
3376  $c = $sargs[$i];
3377 
3378  if ($c == '"') {
3379  if ($bq == $c) $bq = '';
3380  else if (($bq == '') && (strlen(trim($args[$ak])) == 0)) {
3381  $bq = $c;
3382  $args[$ak] = "'";
3383  } else $args[$ak].= $c;
3384  } elseif ($c == ',') {
3385  if (!$bq) {
3386  $args[$ak].= '';
3387  $ak++;
3388  } else {
3389  $args[$ak].= $c;
3390  }
3391  } else {
3392  $args[$ak].= $c;
3393  }
3394  }
3395 
3396  if (count($bargs) > 0) $args = array_merge($bargs, $args);
3397 
3398  foreach ($args as $k => $v) {
3399  if ($v != " ") $v = trim($v);
3400  $mapped = $mapArgs[$v];
3401  if ($mapped) {
3402  if (is_object($mapped)) $args[$k] = & $mapArgs[$v];
3403  else $args[$k] = $mapArgs[$v];
3404  } elseif ($attr = $this->getAttribute($v)) {
3405  if ($attr->inArray()) $args[$k] = $this->getTValue($v, "", $index);
3406  else $args[$k] = $this->GetValue($v);
3407  } else {
3408  if ($v == 'THIS') {
3409  $args[$k] = & $this;
3410  } elseif ($v == 'K') {
3411  $args[$k] = $index;
3412  } elseif (($v[0] == "'") || ($v[0] == '"')) {
3413  $lc = substr($v, -1);
3414  if (($lc == "'") || ($lc == '"')) $v = substr($v, 1, -1);
3415  else $v = substr($v, 1);
3416 
3417  $args[$k] = $v; // not an attribute just text
3418 
3419  }
3420  }
3421  }
3422  $value = call_user_func_array(array(
3423  $staticClass,
3424  $methodName,
3425  ) , $args);
3426  }
3427  } else {
3428  $err = sprintf(_("Method [%s] not exists") , $method);
3429  addWarningMsg($err);
3430  return null;
3431  }
3432  }
3433  return $value;
3434  }
3435  /**
3436  * verify attribute constraint
3437  *
3438  * @param string $attrid attribute identificator
3439  * @return array array of 2 items ("err" + "sug").
3440  * The err is the string error message (empty means no error)
3441  * The sug is an array of possibles corrections
3442  */
3443  final public function verifyConstraint($attrid, $index = - 1)
3444  {
3445  $ok = array(
3446  "err" => "",
3447  "sug" => array()
3448  );
3449  $oattr = $this->getAttribute($attrid);
3450  if (strlen(trim($oattr->phpconstraint)) > 1) {
3451  $ko = array(
3452  "err" => sprintf(_("method %s not found") , $oattr->phpconstraint) ,
3453  "sug" => array()
3454  );
3455  $res = $this->applyMethod($oattr->phpconstraint, $ko, $index);
3456 
3457  if ($res !== true) {
3458  if (!is_array($res)) {
3459  if ($res === false) $res = array(
3460  "err" => _("constraint error")
3461  );
3462  elseif (is_string($res)) $res = array(
3463  "err" => $res
3464  );
3465  } elseif ($res["sug"] && (!is_array($res["sug"]))) $res["sug"] = array(
3466  $res["sug"]
3467  );
3468  if (is_array($res) && $res["err"] != "") $this->constraintbroken = "[$attrid] " . $res["err"];
3469  return $res;
3470  }
3471  }
3472 
3473  return $ok;
3474  }
3475  /**
3476  * verify if constraint ore OK
3477  * @param boolean $stoptofirst stop in first constraint error
3478  * @param array &$info set of information about constraint test
3479  * @return string error message (empty means no error)
3480  */
3481  final public function verifyAllConstraints($stoptofirst = true, &$info = array())
3482  {
3483  $err = "";
3484 
3485  $listattr = $this->GetNormalAttributes();
3486  foreach ($listattr as $k => $v) {
3487  if (strlen($v->phpconstraint) > 1) {
3488  if ($v->inArray()) {
3489  $tv = $this->getTValue($v->id);
3490  for ($i = 0; $i < count($tv); $i++) {
3491  $res = $this->verifyConstraint($v->id, $i);
3492  if ($res["err"] != "") {
3493  $info[$v->id . $i] = array(
3494  "id" => $v->id,
3495  "label" => $v->getLabel() ,
3496  "sug" => $res["sug"],
3497  "err" => $res["err"],
3498  "index" => $i,
3499  "pid" => $v->fieldSet->id
3500  );
3501  if ($stoptofirst) return sprintf("[%s] %s", $v->getLabel() , $res["err"]);
3502  $err = $res["err"];
3503  }
3504  }
3505  } else {
3506  $res = $this->verifyConstraint($v->id);
3507  if ($res["err"] != "") {
3508  $info[$v->id] = array(
3509  "id" => $v->id,
3510  "label" => $v->getLabel() ,
3511  "pid" => $v->fieldSet->id,
3512  "sug" => $res["sug"],
3513  "err" => $res["err"]
3514  );
3515  if ($stoptofirst) return sprintf("[%s] %s", $v->getLabel() , $res["err"]);
3516  $err = $res["err"];
3517  }
3518  }
3519  }
3520  }
3521  return $err;
3522  }
3523  /** return the first attribute of type 'file'
3524  * @return Attribute
3525  */
3526  final public function GetFirstFileAttributes()
3527  {
3528  $t = $this->GetFileAttributes();
3529  if (count($t) > 0) return current($t);
3530  return false;
3531  }
3532  /**
3533  * Add a comment line in history document
3534  * note : modify is call automatically
3535  * @param string $comment the comment to add
3536  * @param string $level level of comment
3537  * @param string $code use when memorize notification
3538  * @param string $uid user identificator : by default its the current user
3539  */
3540  final public function AddComment($comment = '', $level = HISTO_INFO, $code = '', $uid = '')
3541  {
3542  global $action;
3543  if ($this->id == "") return;
3544 
3545  $h = new DocHisto($this->dbaccess);
3546 
3547  $h->id = $this->id;
3548  $h->initid = $this->initid;
3549  if (!isUTF8($comment)) $comment = utf8_encode($comment);
3550  $h->comment = $comment;
3551  $h->date = date("d-m-Y H:i:s");
3552  if ($uid > 0) {
3553  $u = new User("", $uid);
3554  $h->uid = $u->id;
3555  $h->uname = sprintf("%s %s", $u->firstname, $u->lastname);
3556  } else {
3557  $h->uname = sprintf("%s %s", $action->user->firstname, $action->user->lastname);
3558  $h->uid = $action->user->id;
3559  }
3560  $h->level = $level;
3561  $h->code = $code;
3562 
3563  $err = $h->Add();
3564  if ($level == HISTO_ERROR) {
3565  error_log(sprintf("document %s [%d] : %s", $this->title, $this->id, $comment));
3566  }
3567  return $err;
3568  }
3569  /**
3570  * Add a log entry line in log document
3571  *
3572  * @param string $comment the comment to add
3573  * @param string $level level of comment
3574  * @param string $code use when memorize notification
3575  * @param string $arg serialized object
3576  * @param string $uid user identificator : by default its the current user
3577  */
3578  final public function addLog($code = '', $arg = '', $comment = '', $level = '', $uid = '')
3579  {
3580  global $action;
3581  if (($this->id == "") || ($this->doctype == 'T')) return;
3582 
3583  include_once ("FDL/Class.DocLog.php");
3584  $h = new DocLog($this->dbaccess);
3585  $h->id = $this->id;
3586  $h->initid = $this->initid;
3587  $h->title = $this->title;
3588  if (!isUTF8($comment)) $comment = utf8_encode($comment);
3589  $h->comment = $comment;
3590 
3591  if ($uid > 0) {
3592  $u = new User("", $uid);
3593  $h->uid = $u->id;
3594  $h->uname = sprintf("%s %s", $u->firstname, $u->lastname);
3595  } else {
3596  $h->uname = sprintf("%s %s", $action->user->firstname, $action->user->lastname);
3597  $h->uid = $action->user->id;
3598  }
3599  $h->level = $level ? $level : LOG_NOTIFY;
3600  $h->code = $code;
3601  if ($arg) $h->arg = serialize($arg);
3602 
3603  $err = $h->Add();
3604  return $err;
3605  }
3606  /**
3607  * Get history for the document
3608  * @param bool $all set true if want for all revision
3609  *
3610  * @return array of different comment
3611  */
3612  public function getHisto($allrev = false, $code = "", $limit = 0)
3613  {
3614  include_once ("Class.QueryDb.php");
3615  $q = new QueryDb($this->dbaccess, "dochisto");
3616  if ($allrev) $q->AddQuery("initid=" . $this->initid);
3617  else $q->AddQuery("id=" . $this->id);
3618  if ($code) $q->addQuery(sprintf("code='%s'", pg_escape_string($code)));
3619  $q->order_by = "date desc";
3620  $l = $q->Query(0, $limit, "TABLE");
3621 
3622  if (is_array($l)) return $l;
3623  return array();
3624  }
3625  /**
3626  * Add a application tag for the document
3627  * if it is already set no set twice
3628  * @param string $atg the tag to add
3629  * @return string error message
3630  */
3631  final public function addATag($tag)
3632  {
3633  $err = "";
3634  if ($this->atags == "") {
3635  $this->atags = $tag;
3636  $err = $this->modify(true, array(
3637  "atags"
3638  ) , true);
3639  } else {
3640  if (!$this->getATag($tag)) {
3641  $this->atags.= "\n$tag";
3642  $err = $this->modify(true, array(
3643  "atags"
3644  ) , true);
3645  }
3646  }
3647  return $err;
3648  }
3649  /**
3650  * Return true if tag is present
3651  *
3652  * @param string $tag the tag to search
3653  * @return bool
3654  */
3655  final public function getATag($tag)
3656  {
3657  if ($this->atags == "") return false;
3658  return (preg_match("/\b$tag\b/", $this->atags) > 0);
3659  }
3660  /**
3661  * Delete a application tag for the document
3662  *
3663  * @param string $tag the tag to delete
3664  * @return string error message
3665  */
3666  final public function delATag($tag)
3667  {
3668  $err = "";
3669  if ($this->atags == "") return "";
3670  $atags = preg_replace("/\b$tag\b/", "", $this->atags);
3671  $atags = str_replace("\n\n", "\n", $atags);
3672  $atags = preg_replace("/\n$/m", '', $atags);
3673  if ($atags != $this->atags) {
3674  $this->atags = $atags;
3675  $err = $this->modify(true, array(
3676  "atags"
3677  ) , true);
3678  }
3679  return $err;
3680  }
3681  /**
3682  * Add a user tag for the document
3683  * if it is already set no set twice
3684  * @param int $uid the system user identificator
3685  * @param string $tag the key tag
3686  * @param string $datas a comment or a value for the tag
3687  * @param bool $allrevision set to false if attach a tag to a specific version
3688  * @return string error message
3689  */
3690  final public function addUTag($uid, $tag, $datas = "", $allrevision = true)
3691  {
3692  if (!$this->initid) return "";
3693  if ($tag == "") return _("no user tag specified");
3694  $this->delUTag($uid, $tag, $allrevision);
3695 
3696  global $action;
3697  $h = new DocUTag($this->dbaccess);
3698 
3699  $h->id = $this->id;
3700  $h->initid = $this->initid;
3701  $h->fixed = ($allrevision) ? 'false' : 'true';
3702  $h->date = date("d-m-Y H:i:s");
3703  if ($uid > 0) {
3704  $u = new User("", $uid);
3705  $h->uid = $u->id;
3706  $h->uname = sprintf("%s %s", $u->firstname, $u->lastname);
3707  }
3708  $h->fromuid = $action->user->id;
3709 
3710  $h->tag = $tag;
3711  $h->comment = $datas;
3712 
3713  $err = $h->Add();
3714  return $err;
3715  }
3716  /**
3717  * Test if current user has the u tag specified
3718  *
3719  * @param string $tag the tag to verify
3720  * @param bool $allrevision set to false to verify a tag to a specific version
3721  */
3722  final public function hasUTag($tag, $allrevision = true)
3723  {
3724  if (!$this->initid) return false;
3725  include_once ("FDL/Class.DocUTag.php");
3726  $docid = ($allrevision) ? $this->initid : $this->id;
3727  $utag = new DocUTag($this->dbaccess, array(
3728  $docid,
3729  $this->userid,
3730  $tag
3731  ));
3732  return $utag->isAffected();
3733  }
3734  /**
3735  * Get current user tag specified
3736  *
3737  * @param string $tag the tag to verify
3738  * @param bool $allrevision set to false to get a tag to a specific version
3739  * @return DocUTag
3740  */
3741  final public function getUTag($tag, $allrevision = true, $uid = null)
3742  {
3743  if (!$this->initid) return "";
3744  if ($uid === null) {
3745  $uid = $this->userid;
3746  }
3747 
3748  include_once ("FDL/Class.DocUTag.php");
3749  $q = new QueryDb($this->dbaccess, "docUTag");
3750  $q->addQuery("uid=" . intval($uid));
3751  if ($tag) $q->addQuery("tag = '" . pg_escape_string($tag) . "'");
3752  if ($allrevision) $q->addQuery("initid = " . $this->initid);
3753  else $q->addQuery("id = " . $this->id);
3754  $q->order_by = "id desc";
3755  $r = $q->Query(0, 1);
3756  if ($q->nb == 1) return $r[0];
3757  return false;
3758  }
3759  /**
3760  * Remove a user tag for the document
3761  * if it is already set no set twice
3762  * @param int $uid the system user identificator
3763  * @param string $tag the tag to add
3764  * @param bool $allrevision set to false to del a tag to a specific version
3765  * @return string error message
3766  */
3767  final public function delUTag($uid, $tag, $allrevision = true)
3768  {
3769  if ($tag == "") return _("no user tag specified");
3770  include_once ("FDL/Class.DocUTag.php");
3771  $err = "";
3772 
3773  $docid = ($allrevision) ? $this->initid : $this->id;
3774  if ($allrevision) {
3775  $err = $this->exec_query(sprintf("delete from docutag where initid=%d and tag='%s' and uid=%d", $this->initid, pg_escape_string($tag) , $uid));
3776  } else {
3777  $err = $this->exec_query(sprintf("delete from docutag where id=%d and tag='%s' and uid=%d", $this->id, pg_escape_string($tag) , $uid));
3778  }
3779  return $err;
3780  }
3781  /**
3782  * Remove all user tag for the document
3783  *
3784  * @param int $uid the system user identificator
3785  * @return string error message
3786  */
3787  final public function delUTags($uid = "")
3788  {
3789  if (!$this->initid) return "";
3790  if (!$uid) $uid = $this->userid;
3791  $err = $this->exec_query(sprintf("delete from docutag where initid=%d and uid=%d", $this->initid, $uid));
3792 
3793  return $err;
3794  }
3795  /**
3796  * Refresh all user tag for the document in case of revision
3797  * @return string error message
3798  */
3799  final public function refreshUTags()
3800  {
3801  if (!$this->initid) return "";
3802  include_once ("FDL/Class.DocUTag.php");
3803  $q = new QueryDb($this->dbaccess, "docUTag");
3804  $q->Query(0, 0, "TABLE", sprintf("update docutag set id=%d where initid=%d and (not fixed)", $this->id, $this->initid));
3805 
3806  return $err;
3807  }
3808  /**
3809  * search all user tag for the document
3810  * @param string $tag tag to search
3811  * @param boolean $allrevision view tags for all revision
3812  * @param boolean $allusers view tags of all users
3813  * @return array user tags key=>value
3814  */
3815  final public function searchUTags($tag = "", $allrevision = true, $allusers = false)
3816  {
3817  if (!$this->initid) return "";
3818  include_once ("FDL/Class.DocUTag.php");
3819  $q = new QueryDb($this->dbaccess, "docUTag");
3820  if (!$allusers) $q->addQuery("uid=" . intval($this->userid));
3821  if ($tag) $q->addQuery("tag = '" . pg_escape_string($tag) . "'");
3822  if ($allrevision) $q->addQuery("initid = " . $this->initid);
3823  else $q->addQuery("id = " . $this->id);
3824  $r = $q->Query(0, 0, "TABLE");
3825  if ($q->nb == 0) $r = array();
3826  return $r;
3827  }
3828  /**
3829  * get ask for current users
3830  * @param bool $control if false all associated askes else only askes available for current user
3831  * @return array
3832  */
3833  public function getWasks($control = true)
3834  {
3835  $t = array();
3836  if ($this->wid > 0 && $this->locked == - 1 && $this->doctype != 'Z' && $this->state) {
3837  $wdoc = new_doc($this->dbaccess, $this->wid);
3838  if ($wdoc->isAlive()) {
3839  $wdoc->set($this);
3840  $waskids = $wdoc->getDocumentWasks($this->state, $control);
3841  foreach ($waskids as $k => $waskid) {
3842  $wask = new_doc($this->dbaccess, $waskid);
3843  if ($wask->isAlive()) {
3844  $ut = $this->getUTag("ASK_" . $wask->id, false);
3845  if ($ut) $answer = $ut->comment;
3846  else $answer = "";
3847  $t[] = array(
3848  "waskid" => $wask->id,
3849  "ask" => $wask->getValue("was_ask") ,
3850  "key" => $answer,
3851  "label" => $wask->getAskLabel($answer)
3852  );
3853  }
3854  }
3855  }
3856  }
3857  return $t;
3858  }
3859  /**
3860  * set a answer for a document for a ask (for current user)
3861  * @param int $waskid the identificator of wask
3862  */
3863  function setWaskAnswer($waskid, $answer)
3864  {
3865  $err = _("setWaskAnswer::invalid parameters");
3866  $waskid = intval($waskid);
3867  if ($waskid && $answer) {
3868  if (is_array($answer)) $answer = $this->_array2val($answer);
3869  $err = $this->addUTag($this->userid, "ASK_" . intval($waskid) , $answer, false);
3870  return $err;
3871  }
3872  return $err;
3873  }
3874  /**
3875  * all ask are answer ?
3876  * @return bool true if all ask are answer or when has no askes
3877  */
3878  function askIsCompleted()
3879  {
3880  $ans = $this->getWasks();
3881  foreach ($ans as $an) {
3882  if (!$an["key"]) return false;
3883  }
3884  return true;
3885  }
3886  /**
3887  * return the latest document id in history of a document which has ask
3888  * @return int the identificator
3889  */
3891  {
3892  if (!$this->wid) return false;
3893  $ldoc = $this->GetRevisions("TABLE");
3894  $wdoc = new_doc($this->dbaccess, $this->wid);
3895  if ($wdoc->isAlive()) {
3896  $wdoc->set($this);
3897  foreach ($ldoc as $k => $v) {
3898  $aask = $wdoc->attrPrefix . "_ASKID" . ($v["state"]);
3899  if ($v["locked"] == - 1 && $wdoc->getValue($aask)) {
3900  if ($wdoc->getValue($aask)) return $v["id"];
3901  }
3902  }
3903  }
3904  return false;
3905  }
3906  /**
3907  * verify if document is really fixed
3908  * @return bool
3909  */
3910  function isFixed()
3911  {
3912  return isFixedDoc($this->dbaccess, $this->id);
3913  }
3914  /**
3915  * Create a new revision of a document
3916  * the current document is revised (became a fixed document)
3917  * a new revision is created
3918  * @param string $comment the comment of the revision
3919  * @return string error text (empty if no error)
3920  */
3921  final public function addRevision($comment = '')
3922  {
3923  // first control
3924  if ($this->locked == - 1) return _("document already revised");
3925  if ($this->isFixed()) {
3926  $err = _("document already revised");
3927  $this->Addcomment($err, HISTO_ERROR, "REVERROR");
3928  return $err;
3929  }
3930  if (!$this->withoutControl) {
3931  $err = $this->Control("edit");
3932  if ($err != "") return ($err);
3933  }
3934  $fdoc = $this->getFamDoc();
3935 
3936  if ($fdoc->schar == "S") return sprintf(_("the document of %s family cannot be revised") , $fdoc->title);
3939  $postitid = $this->postitid; // transfert post-it to latest revision
3940  $forumid = $this->forumid; // transfert forum to latest revision
3941  $this->locked = - 1; // the file is archived
3942  $this->lmodify = 'N'; // not locally modified
3943  $this->allocated = 0; // cannot allocated fixed document
3944  $this->owner = $this->userid; // rev user
3945  $this->postitid = 0;
3946  $this->forumid = 0;
3947  $date = gettimeofday();
3948  $this->revdate = $date['sec']; // change rev date
3949  $point = "revision" . $this->id;
3950  $this->savePoint($point);
3951  if ($comment != '') $this->Addcomment($comment, HISTO_MESSAGE, "REVISION");
3952  $err = $this->modify();
3953  if ($err != "") {
3954  $this->rollbackPoint($point);
3955  //$this->exec_query("rollback;");
3956  $this->select($this->id); // reset db values
3957  return $err;
3958  }
3959  // double control
3960  if (!$this->isFixed()) {
3961  $err = sprintf("track error revision [%s]", pg_last_error($this->dbid));
3962  $this->Addcomment($err, HISTO_ERROR, "REVERROR");
3963  $this->commitPoint($point);
3964  return $err;
3965  }
3966 
3967  $fa = $this->GetFileAttributes(true); // copy cached values
3968  $ca = array();
3969  foreach ($fa as $k => $v) {
3970  $ca[] = $v->id . "_txt";
3971  }
3972  $this->AffectColumn($ca);
3973  foreach ($ca as $a) {
3974  if ($this->$a != "") $this->fields[$a] = $a;
3975  }
3976  //$listvalue = $this->GetValues(); // save copy of values
3977  // duplicate values
3978  $olddocid = $this->id;
3979  $this->id = "";
3980 
3981  if ($locked > 0) $this->locked = $locked; // report the lock
3982  else $this->locked = 0;
3983  $this->allocated = $allocated; // report the allocate
3984  $this->comment = ""; // change comment
3985  $this->revision = $this->revision + 1;
3986  $this->postitid = $postitid;
3987  $this->forumid = $forumid;
3988 
3989  $err = $this->Add();
3990  if ($err != "") {
3991  // restore last revision
3992  // $this->exec_query("rollback;");
3993  $this->rollbackPoint($point);
3994 
3995  $this->select($olddocid); // reset db values
3996  return $err;
3997  }
3998 
3999  $this->commitPoint($point);
4000 
4001  $this->refresh(); // to recompute possible dynamic profil variable
4002  if ($this->dprofid > 0) $this->setProfil($this->dprofid); // recompute profil if needed
4003  $err = $this->modify(); // need to applicate SQL triggers
4004  $this->UpdateVaultIndex();
4005  $this->refreshUTags();
4006  if ($err == "") {
4007  $this->addLog("revision", array(
4008  "id" => $this->id,
4009  "initid" => $this->initid,
4010  "revision" => $this->revision,
4011  "title" => $this->title,
4012  "fromid" => $this->fromid,
4013  "fromname" => $this->fromname
4014  ));
4015  // max revision
4016  $fdoc = $this->getFamDoc();
4017  $maxrev = intval($fdoc->maxrev);
4018  if ($maxrev > 0) {
4019  if ($this->revision > $maxrev) {
4020  // need delete first revision
4021  $revs = $this->getRevisions("TABLE", "ALL");
4022  for ($i = $maxrev; $i < count($revs); $i++) {
4023  $d = getDocObject($this->dbaccess, $revs[$i]);
4024  if ($d) $d->ReallyDelete(true);
4025  }
4026  }
4027  }
4028  }
4029 
4030  return $err;
4031  }
4032  /**
4033  * Set a free state to the document
4034  * for the document without workflow
4035  * a new revision is created
4036  * @param string $newstateid the document id of the state (FREESTATE family)
4037  * @param string $comment the comment of the state change
4038  * @param bool $revision if false no revision are made
4039  * @return string error text (empty if no error)
4040  */
4041  final public function changeFreeState($newstateid, $comment = '', $revision = true)
4042  {
4043  if ($this->wid > 0) return sprintf(_("cannot set free state in workflow controlled document %s") , $this->title);
4044  if ($this->wid == - 1) return sprintf(_("cannot set free state for document %s: workflow not allowed") , $this->title);
4045  if (!$this->isRevisable()) return sprintf(_("cannot set free state for document %s: document cannot be revised") , $this->title);
4046  if ($newstateid == 0) {
4047  $this->state = "";
4048  $err = $this->modify(false, array(
4049  "state"
4050  ));
4051  if ($err == "") {
4052  $comment = sprintf(_("remove state : %s") , $comment);
4053  if ($revision) $err = $this->addRevision($comment);
4054  else $err = $this->addComment($comment);
4055  }
4056  } else {
4057 
4058  $state = new_doc($this->dbaccess, $newstateid);
4059  if (!$state->isAlive()) return sprintf(_("invalid freestate document %s") , $newstateid);
4060  if ($state->fromid != 39) return sprintf(_("not a freestate document %s") , $state->title);
4061 
4062  $this->state = $state->id;
4063  $err = $this->modify(false, array(
4064  "state"
4065  ));
4066  if ($err == "") {
4067  $comment = sprintf(_("change state to %s : %s") , $state->title, $comment);
4068  if ($revision) $err = $this->addRevision($comment);
4069  else $err = $this->addComment($comment);
4070  }
4071  }
4072  return $err;
4073  }
4074  /**
4075  * set state for a document controled by a workflow
4076  *
4077  * @param string $newstate the new state
4078  * @param string $comment optionnal comment to set in history
4079  * @param bool $force is true when it is the second passage (without interactivity)
4080  * @param bool $withcontrol set to false if you want to not verify control permission ot transition
4081  * @param bool $wm1 set to false if you want to not apply m1 methods
4082  * @param bool $wm2 set to false if you want to not apply m2 methods
4083  * @param bool $need set to false if you want to not verify needed attribute are set
4084  * @return string the state - empty if no state
4085  */
4086  final public function setState($newstate, $comment = '', $force = false, $withcontrol = true, $wm1 = true, $wm2 = true, $wneed = true)
4087  {
4088  if ($newstate == "") return _("no state specified");
4089  if (!$this->wid) return _("document is not controlled by a workflow");
4090  $wdoc = new_doc($this->dbaccess, $this->wid);
4091  if (!$wdoc->isAlive()) return _("assigned workflow is not alive");
4092  try {
4093  $wdoc->Set($this);
4094  $err = $wdoc->ChangeState($newstate, $comment, $force, $withcontrol, $wm1, $wm2, $wneed);
4095  }
4096  catch(Exception $e) {
4097  $err = sprintf(_("workflow associated %s [%d] is corrupted") , $wdoc->title, $wdoc->id);
4098  }
4099  return $err;
4100  }
4101  /**
4102  * return the state of a document
4103  * if document has workflow it is the key
4104  * if document state is a free state it is the name of the state
4105  *
4106  * @return string the state - empty if no state
4107  */
4108  public function getState()
4109  {
4110  if ($this->wid > 0) return $this->state;
4111  if (is_numeric($this->state) && ($this->state > 0)) {
4112  $state = $this->getTitle($this->state);
4113  return $state;
4114  }
4115 
4116  return $this->state;
4117  }
4118  /**
4119  * return the color associated for the state of a document
4120  * if document has workflow : the color state
4121  * if document state is a free state the color
4122  *
4123  * @return string the color of the state - empty if no state
4124  */
4125  public function getStateColor($def = "")
4126  {
4127  if ($this->wid > 0) {
4128  $wdoc = new_Doc($this->dbaccess, $this->wid);
4129  if ($wdoc->isAffected()) return $wdoc->getColor($this->state, $def);
4130  } else {
4131  if (is_numeric($this->state) && ($this->state > 0)) {
4132  $state = $this->getDocValue($this->state, "frst_color", $def);
4133  return $state;
4134  }
4135  }
4136  return $def;
4137  }
4138  /**
4139  * return the action associated for the state of a document
4140  * if document has workflow : the action label description
4141  * if document state is a free state description
4142  *
4143  * @return string the color of the state - empty if no state
4144  */
4145  final public function getStateActivity($def = "")
4146  {
4147  if ($this->wid > 0) {
4148  $wdoc = new_Doc($this->dbaccess, $this->wid);
4149  if ($wdoc->isAffected()) return $wdoc->getActivity($this->state, $def);
4150  } else {
4151  if (is_numeric($this->state) && ($this->state > 0)) {
4152  $stateact = $this->getDocValue($this->state, "frst_desc", $def);
4153  return $stateact;
4154  }
4155  }
4156  return $def;
4157  }
4158  /**
4159  * return the copy of the document
4160  * the copy is created to the database
4161  * the profil of the copy is the default profil according to his family
4162  * the copy is not locked and if it is related to a workflow, his state is the first state
4163  * @param bool $temporary if true the document create it as temporary document
4164  * @param bool $control if false don't control acl create (generaly use when temporary is true)
4165  * @param bool $linkfld if true and document is a folder then document included in folder are also inserted in the copy (are not duplicated) just linked
4166  * @param bool $copyfile if true duplicate files of the document
4167  * @return Doc in case of error return a string that indicate the error
4168  */
4169  final public function Copy($temporary = false, $control = true, $linkfld = false, $copyfile = false)
4170  {
4171 
4172  $copy = createDoc($this->dbaccess, $this->fromid, $control);
4173  if (!is_object($copy)) return false;
4174 
4175  $copy->transfertValuesFrom($this);
4176 
4177  $copy->id = "";
4178  $copy->initid = "";
4179  $copy->revision = "0";
4180  $copy->locked = "0";
4181  $copy->allocated = "0";
4182  $copy->state = "";
4183  $copy->comment = "";
4184  $copy->icon = $this->icon;;
4185 
4186  if ($temporary) {
4187  $copy->doctype = "T";
4188  $copy->profid = 0;
4189  $copy->dprofid = 0;
4190  } else {
4191  $cdoc = $this->getFamDoc();
4192  $copy->setProfil($cdoc->cprofid);
4193  }
4194 
4195  $err = $copy->PreCopy($this);
4196  if ($err != "") return $err;
4197 
4198  $err = $copy->Add();
4199  if ($err != "") return $err;
4200  $copy->addComment(sprintf(_("copy from document #%d -%s-") , $this->id, $this->title));
4201 
4202  if ($copyfile) $copy->duplicateFiles();
4203 
4204  $copy->PostCopy($this);
4205  if ($err != "") AddWarningMsg($err);
4206 
4207  $copy->Modify();
4208  if ($linkfld && method_exists($copy, "insertFolder")) {
4209  $copy->insertFolder($this->initid);
4210  }
4211 
4212  return $copy;
4213  }
4214 
4215  function PreCopy(&$copyfrom)
4216  {
4217  // to be defined in child class
4218  return "";
4219  }
4220 
4221  function PostCopy(&$copyfrom)
4222  {
4223  // to be defined in child class
4224  return "";
4225  }
4226 
4227  final public function translate($docid, $translate)
4228  {
4229  $doc = new_Doc($this->dbaccess, $docid);
4230  if ($doc->isAlive()) {
4231  foreach ($translate as $afrom => $ato) {
4232  $this->setValue($ato, $doc->getValue($afrom));
4233  }
4234  }
4235  }
4236  /**
4237  * Put document in an archive
4238  * @param _ARCHIVING $archive the archive document
4239  */
4240  final public function archive(&$archive)
4241  {
4242  $err = "";
4243  if ($this->archiveid == 0) {
4244  if ($this->doctype == "C") $err = sprintf("families cannot be archieved");
4245  elseif (!$this->withoutControl) $err = $this->control("edit");
4246  if ($err == "") {
4247  $this->locked = 0;
4248  $this->archiveid = $archive->id;
4249  $this->dprofid = ($this->dprofid > 0) ? (-$this->dprofid) : (-abs($this->profid));
4250  $archprof = $archive->getValue("arc_profil");
4251  $this->profid = $archprof;
4252  $err = $this->modify(true, array(
4253  "locked",
4254  "archiveid",
4255  "dprofid",
4256  "profid"
4257  ) , true);
4258  if (!$err) {
4259  $this->addComment(sprintf(_("Archiving into %s") , $archive->getTitle()) , HISTO_MESSAGE, "ARCHIVE");
4260  $this->addLog('archive', $archive->id, sprintf(_("Archiving into %s") , $archive->getTitle()));
4261  $err = $this->exec_query(sprintf("update doc%d set archiveid=%d, dprofid=-abs(profid), profid=%d where initid=%d and locked = -1", $this->fromid, $archive->id, $archprof, $this->initid));
4262  }
4263  }
4264  } else $err = sprintf("document is already archived");
4265 
4266  return $err;
4267  }
4268  /**
4269  * Delete document in an archive
4270  * @param _ARCHIVING $archive the archive document
4271  */
4272  final public function unArchive(&$archive)
4273  {
4274  $err = "";
4275 
4276  if ($this->archiveid == $archive->id) {
4277  if (!$this->withoutControl) $err = $this->control("edit");
4278  if ($err == "") {
4279  $this->locked = 0;
4280  $this->archiveid = ""; // set to null
4281  $restoreprofil = abs($this->dprofid);
4282  $this->dprofid = 0;
4283  $err = $this->setProfil($restoreprofil);
4284  if (!$err) $err = $this->modify(true, array(
4285  "locked",
4286  "archiveid",
4287  "dprofid",
4288  "profid"
4289  ) , true);
4290  if (!$err) {
4291  $this->addComment(sprintf(_("Unarchiving from %s") , $archive->getTitle()) , HISTO_MESSAGE, "UNARCHIVE");
4292  $this->addLog('unarchive', $archive->id, sprintf(_("Unarchiving from %s") , $archive->getTitle()));
4293  $err = $this->exec_query(sprintf("update doc%d set archiveid=null, profid=abs(dprofid), dprofid=null where initid=%d and locked = -1", $this->fromid, $this->initid));
4294  }
4295  }
4296  } else $err = sprintf("document not archived");
4297 
4298  return $err;
4299  }
4300  /**
4301  * lock document
4302  *
4303  * the auto lock is unlocked when the user discard edition or when he's modify document
4304  * @param bool $auto if true it is a automatic lock due to an edition (@see editcard()}
4305  * @param int $userid if set lock with another userid, the edit control will be disabled
4306  *
4307  * @return string error message, if no error empty string, if message
4308  * @see Doc::CanLockFile()
4309  * @see Doc::unlock()
4310  */
4311  final public function lock($auto = false, $userid = "")
4312  {
4313 
4314  $err = "";
4315  if ($userid == "") {
4316  $err = $this->CanLockFile();
4317  if ($err != "") return $err;
4318  $userid = $this->userid;
4319  } else {
4320  $this->disableEditControl();
4321  }
4322  // test if is not already locked
4323  if ($auto) {
4324  if (($userid != 1) && ($this->locked == 0)) {
4325  $this->locked = - $userid; // in case of auto lock the locked id is negative
4326  $err = $this->modify(false, array(
4327  "locked"
4328  ));
4329  if (!$err) $this->addLog('lock');
4330  }
4331  } else {
4332  if (($this->locked != $userid) || ($this->lockDomain)) {
4333  $this->locked = $userid;
4334  $err = $this->modify(false, array(
4335  "locked"
4336  ));
4337  if (!$err) $this->addLog('lock');
4338  }
4339  }
4340  $this->enableEditControl();
4341 
4342  return $err;
4343  }
4344  /**
4345  * unlock document
4346  *
4347  * the automatic unlock is done only if the lock has been set automatically also
4348  * the explicit unlock, unlock in all case (if CanUnLockFile)
4349  * @param bool $auto if true it is a automatic unlock
4350  * @param bool $force if true no control oif can unlock
4351  *
4352  * @return string error message, if no error empty string
4353  * @see Doc::CanUnLockFile()
4354  * @see Doc::lock()
4355  */
4356  final public function unLock($auto = false, $force = false)
4357  {
4358  if ($this->locked == 0) return "";
4359  if (!$force) $err = $this->CanUnLockFile();
4360  if ($err != "") return $err;
4361 
4362  if ($auto) {
4363  if ($this->locked < - 1) {
4364  $this->locked = "0";
4365  $this->modify(false, array(
4366  "locked"
4367  ));
4368  if (!$err) $this->addLog('unlock');
4369  }
4370  } else {
4371  if ($this->locked != - 1) {
4372  $this->locked = "0";
4373  $this->lockdomainid = '';
4374  $this->modify(false, array(
4375  "locked",
4376  "lockdomainid"
4377  ));
4378  if (!$err) $this->addLog('unlock');
4379  }
4380  }
4381 
4382  return "";
4383  }
4384  /**
4385  * allocate document
4386  *
4387  * affect a document to a user
4388  * @param int $userid the system identificator of the user to affect
4389  * @param bool $revision if false no revision are made
4390  * @param bool $autolock if false no lock are made
4391  *
4392  * @return string error message, if no error empty string, if message
4393  */
4394  final public function allocate($userid, $comment = "", $revision = false, $autolock = true)
4395  {
4396 
4397  $err = "";
4398  $err = $this->canEdit();
4399  if ($err != "") $err = _("Affectation aborded") . "\n" . $err;
4400  if ($err == "") {
4401  $u = new User("", $userid);
4402  if ($u->isAffected()) {
4403  if ($err != "") $err = _("Affectation aborded") . "\n" . $err;
4404  // no test if allocated can edit document
4405  //$err=$this->ControlUser($u->id,"edit");
4406  //if ($err != "") $err=sprintf(_("Affectation aborded\n%s for user %s %s"),$err,$u->firstname,$u->lastname);
4407  if ($err == "") {
4408  $this->addComment(sprintf(_("Affected to %s %s") , $u->firstname, $u->lastname));
4409  if ($comment) {
4410  if ($revision) {
4411  $this->addRevision(sprintf(_("Affected for %s") , $comment));
4412  } else {
4413  $this->addComment(sprintf(_("Affected for %s") , $comment));
4414  }
4415  }
4416  $this->addLog('allocate', array(
4417  "allocated" => array(
4418  "id" => $u->id,
4419  "firstname" => $u->firstname,
4420  "lastname" => $u->lastname
4421  )
4422  ));
4423 
4424  $this->delUTag("AFFECTED");
4425  $this->addUTag($userid, "AFFECTED", $comment);
4426  if ($autolock) $err = $this->lock(false, $userid);
4427  }
4428  } else {
4429  $err = _("Affectation aborded : user not know");
4430  }
4431  }
4432  if ($err == "") {
4433  $this->allocated = $userid;
4434  $this->modify(true, array(
4435  "allocated"
4436  ) , true);
4437  }
4438 
4439  return $err;
4440  }
4441  /**
4442  * unallocate document
4443  *
4444  * unaffect a document to a user
4445  * only the allocated user can unallocate and also users which has unlock acl
4446  * @param bool $revision if false no revision are made
4447  *
4448  * @return string error message, if no error empty string, if message
4449  */
4450  final public function unallocate($comment = "", $revision = true)
4451  {
4452  if ($this->allocated == 0) return "";
4453  $err = "";
4454  $err = $this->canEdit();
4455  if ($err == "") {
4456  if ((!$this->withoutControl) && ($this->userid != $this->allocated)) $err = $this->control("unlock");
4457  }
4458 
4459  if ($err == "") {
4460  $u = new User("", $this->allocated);
4461  if ($u->isAffected()) {
4462  $err = $this->unlock();
4463  if ($err == "") {
4464  $this->delUTag("AFFECTED");
4465  if ($revision) $this->addRevision(sprintf(_("Unallocated of %s %s : %s") , $u->firstname, $u->lastname, $comment));
4466  else $this->addComment(sprintf(_("Unallocated of %s %s: %s") , $u->firstname, $u->lastname, $comment));
4467  }
4468  } else {
4469  $err = _("user not know");
4470  }
4471  }
4472  if ($err == "") {
4473  $this->allocated = 0;
4474  $this->modify(true, array(
4475  "allocated"
4476  ) , true);
4477  $this->addLog('unallocate');
4478  }
4479 
4480  if ($err != "") $err = _("Unallocate aborded") . "\n" . $err;
4481  return $err;
4482  }
4483  /**
4484  * return icon url
4485  * if no icon found return doc.gif
4486  * @return string icon url
4487  */
4488  final public function getIcon($idicon = "", $size = null)
4489  {
4490 
4491  global $action;
4492  if ($idicon == "") $idicon = $this->icon;
4493  if ($idicon != "") {
4494 
4495  if (preg_match(PREGEXPFILE, $idicon, $reg)) {
4496  if ($size) {
4497  $efile = "resizeimg.php?vid=" . $reg[2] . "&size=" . $size;
4498  } else {
4499  $efile = "FDL/geticon.php?vaultid=" . $reg[2] . "&mimetype=" . $reg[1];
4500  }
4501  } else {
4502  $efile = $action->parent->GetImageUrl($idicon, true, $size);
4503  }
4504  return $efile;
4505  } else {
4506  if ($this->fromid == 0) {
4507 
4508  return $action->GetImageUrl("doc.gif", true, $size);
4509  }
4510  //$fdoc = new_Doc(newDoc($this->dbaccess, $this->fromid);
4511  return $action->GetImageUrl("doc.gif", true, $size);
4512  // don't recursivity to increase speed
4513  // return $fdoc->geticon();
4514 
4515  }
4516  }
4517  // change icon for a class or a simple doc
4518  final public function changeIcon($icon)
4519  {
4520 
4521  if ($this->doctype == "C") { // a class
4523  if ($this->icon != "") {
4524  // need disabled triggers to increase speed
4525  $qt[] = "begin";
4526  $qt[] = "ALTER TABLE doc$fromid DISABLE TRIGGER ALL";
4527  $qt[] = "update doc$fromid set icon='$icon' where (fromid=" . $fromid . ") AND (doctype != 'C') and ((icon='" . $this->icon . "') or (icon is null))";
4528  $qt[] = "ALTER TABLE doc$fromid ENABLE TRIGGER ALL";
4529  $qt[] = "update docread set icon='$icon' where (fromid=" . $fromid . ") AND (doctype != 'C') and ((icon='" . $this->icon . "') or (icon is null))";
4530  $qt[] = "commit";
4531 
4532  $this->exec_query(implode(";", $qt));
4533  } else {
4534  $q = "update doc$fromid set icon='$icon' where (fromid=" . $fromid . ") AND (doctype != 'C') and (icon is null)";
4535  $this->exec_query($q);
4536  }
4537  }
4538  // $this->title = AddSlashes($this->title);
4539  $this->icon = $icon;
4540  $this->Modify();
4541  }
4542  /**
4543  * declare a dependance between several attributes
4544  * @param string $in attributes id use for compute $out attributes separates by commas
4545  * @param string $out attributes id calculated by $in attributes separates by commas
4546  */
4547  final public function AddParamRefresh($in, $out)
4548  {
4549  // to know which attribut must be disabled in edit mode
4550  $tin = explode(",", strtolower($in));
4551  $tout = explode(",", strtolower($out));
4552  $this->paramRefresh["$in:$out"] = array(
4553  "in" => $tin,
4554  "out" => $tout
4555  );
4556  }
4557  /**
4558  * compute new visibility with depended attributes
4559  * @return array of visibilities computed with dependance between attributes
4560  */
4561  public function getRefreshVisibility()
4562  {
4563  $tv = array();
4564  foreach ($this->attributes->attr as $k => $v) {
4565  $tv[$v->id] = $v->mvisibility;
4566  }
4567  foreach ($this->paramRefresh as $k => $v) {
4568  reset($v["in"]);
4569  $val = true;
4570  while ($val && (list($ka, $va) = each($v["in"]))) {
4571  $val = $this->getValue($va);
4572  }
4573  if ($val) {
4574  foreach ($v["out"] as $oa) {
4575  if (($tv[$oa] == "W") || ($tv[$oa] == "O")) $tv[$oa] = "S";
4576  }
4577  }
4578  }
4579 
4580  return $tv;
4581  }
4582  /**
4583  * Special Refresh
4584  * to define in child classes
4585  */
4586  function SpecRefresh()
4587  {
4588  }
4589  /**
4590  * Special Refresh Generated automatically
4591  * is defined in generated child classes
4592  */
4593  function SpecRefreshGen($onlyspec = false)
4594  {
4595  }
4596  /**
4597  * recompute all calculated attribut
4598  * and save the document in database if changes occurred
4599  */
4600  final public function Refresh()
4601  {
4602  if ($this->locked == - 1) return; // no refresh revised document
4603  if (($this->doctype == 'C') || ($this->doctype == 'Z')) return; // no refresh for family and zombie document
4604  if ($this->lockdomainid > 0) return '';
4605  $changed = $this->hasChanged;
4606  if (!$changed) $this->disableEditControl(); // disabled control just to refresh
4607  $err = $this->SpecRefresh();
4608  // if ($this->id == 0) return; // no refresh for no created document
4609  $err.= $this->SpecRefreshGen();
4610  if ($this->hasChanged) {
4611  $err.= $this->modify(); // refresh title
4612 
4613  }
4614  if (!$changed) $this->enableEditControl();
4615  return $err;
4616  }
4617  /**
4618  * Recompute file name in concordance with rn option
4619  *
4620  */
4621  function refreshRn()
4622  {
4623  $err = "";
4624  $fa = $this->GetFileAttributes();
4625  foreach ($fa as $aid => $oa) {
4626  $rn = $oa->getOption("rn");
4627  if ($rn) {
4628  if ($oa->inArray()) {
4629  $t = $this->getTvalue($oa->id);
4630  foreach ($t as $k => $v) {
4631  $cfname = $this->vault_filename($oa->id, false, $k);
4632  if ($cfname) {
4633  $fname = $this->applyMethod($rn, "", $k, array(
4634  $cfname
4635  ));
4636  if ($fname != $cfname) {
4637  $err.= $this->renameFile($oa->id, $fname, $k);
4638  }
4639  }
4640  }
4641  } else {
4642  $cfname = $this->vault_filename($oa->id);
4643  if ($cfname) {
4644  $fname = $this->applyMethod($rn, "", -1, array(
4645  $cfname
4646  ));
4647  if ($fname != $cfname) {
4648  $err.= $this->renameFile($oa->id, $fname);
4649  }
4650  }
4651  }
4652  }
4653  }
4654  return $err;
4655  }
4656 
4657  final public function urlWhatEncode($link, $k = - 1)
4658  {
4659  global $action;
4660  $dbaccess = $action->GetParam("FREEDOM_DB");
4661  $urllink = "";
4662  $mi = strlen($link);
4663  for ($i = 0; $i < $mi; $i++) {
4664  switch ($link[$i]) {
4665  case '%':
4666  $i++;
4667  if ($link[$i] == "%") {
4668  $urllink.= "%"; // %% is %
4669 
4670  } else {
4671  if ($link[$i + 1] == "%") {
4672  // special link
4673  switch ($link[$i]) {
4674  case "B": // baseurl
4675  $urllink.= $action->GetParam("CORE_BASEURL");
4676  break;
4677 
4678  case "S": // standurl
4679  $urllink.= $action->GetParam("CORE_STANDURL");
4680  break;
4681 
4682  case "I": // id
4683  $urllink.= $this->id;
4684  break;
4685 
4686  case "T": // title
4687  $urllink.= $this->title;
4688  break;
4689 
4690  default:
4691 
4692  break;
4693  }
4694  $i++; // skip end '%'
4695 
4696  } else {
4697 
4698  $sattrid = "";
4699  while (($i < $mi) && ($link[$i] != "%")) {
4700  $sattrid.= $link[$i];
4701  $i++;
4702  }
4703  $oa = $this->GetAttribute($sattrid);
4704  if (($k >= 0) && ($oa && $oa->repeat)) {
4705  $tval = $this->GetTValue($sattrid);
4706  $ovalue = chop($tval[$k]);
4707  } else {
4708  $ovalue = $this->GetValue($sattrid);
4709  }
4710  if ($ovalue == "") return false;
4711  //$urllink.=urlencode($ovalue); // encode because url values must be encoded
4712  //$urllink.=urlencode($ovalue); // not encode cause url will became invalid
4713  if ($ovalue[0] == '[') $urllink.= urlencode($ovalue);
4714  else if (strstr($ovalue, "\n")) $urllink.= str_replace("\n", '\n', $ovalue);
4715  else $urllink.= ($ovalue); // not encode cause url will became invalid
4716 
4717  }
4718  }
4719  break;
4720 
4721  case '{':
4722  $i++;
4723 
4724  $sattrid = "";
4725  while ($link[$i] != '}') {
4726  $sattrid.= $link[$i];
4727  $i++;
4728  }
4729  // print "attr=$sattrid";
4730  $ovalue = $action->GetParam($sattrid);
4731  $urllink.= $ovalue;
4732 
4733  break;
4734 
4735  default:
4736  $urllink.= $link[$i];
4737  }
4738  }
4739  $urllink = $this->urlWhatEncodeSpec($urllink); // complete in special case families
4740  return (chop($urllink));
4741  }
4742  /**
4743  * virtual method must be use in child families if needed complete url
4744  */
4745  public function urlWhatEncodeSpec($l)
4746  {
4747  return $l;
4748  }
4749 
4750  public static function _val2array($v)
4751  {
4752  if ($v === "" || $v === null) return array();
4753  return explode("\n", str_replace("\r", "", $v));
4754  }
4755 
4756  public static function _array2val($v, $br = '<BR>')
4757  {
4758  $v = str_replace("\n", $br, $v);
4759  if (count($v) == 0) return "";
4760  return implode("\n", $v);
4761  }
4762  /**
4763  * return an url
4764  * @return string the url anchor
4765  */
4766  public function getRssLink()
4767  {
4768  global $action;
4769  return sprintf("%s?app=FREEDOM&action=FREEDOM_RSS&authtype=open&privateid=%s&id=%s", $action->getParam("CORE_OPENURL", $action->getParam("CORE_EXTERNURL")) , $action->user->getUserToken() , $this->id);
4770  }
4771  /**
4772  * return an url for file attribute
4773  * @param string $attrid attribute identificator
4774  * @param int $index set to row rank if it is in array else use -1
4775  * @param bool $cache set to true if file may be persistent in client cache
4776  * @param bool $inline set to true if file must be displayed in web browser
4777  * @return string the url anchor
4778  */
4779  public function getFileLink($attrid, $index = - 1, $cache = false, $inline = false)
4780  {
4781  global $action;
4782  if ($index >= 0) $avalue = $this->getTValue($attrid, "", $index);
4783  else $avalue = $this->getValue($attrid);
4784  if (preg_match(PREGEXPFILE, $avalue, $reg)) {
4785  $vid = $reg[2];
4786  if (true) {
4787  // will be rewrited by apache rules
4788  return sprintf("file/%s/%d/%s/%s/%s?cache=%s&inline=%s", $this->id, $vid, $attrid, $index, rawurlencode($reg[3]) , $cache ? "yes" : "no", $inline ? "yes" : "no");
4789  } else {
4790  return sprintf("%s?app=FDL&action=EXPORTFILE&cache=%s&inline=%s&vid=%s&docid=%s&attrid=%s&index=%d", "", $cache ? "yes" : "no", $inline ? "yes" : "no", $vid, $this->id, $attrid, $index);
4791  }
4792  }
4793  }
4794  /**
4795  * return an html anchor to a document
4796  * @param int $id identificator of document
4797  * @param string $target window target
4798  * @param bool $htmllink must be true else return nothing
4799  * @param string $title should we override default title
4800  * @param bool $js should we add a javascript contextual menu
4801  * @param string $docrev style of link (default:latest, other values: fixed or state(xxx))
4802  * @return string the html anchor
4803  */
4804  final public function getDocAnchor($id, $target = "_self", $htmllink = true, $title = false, $js = true, $docrev = "latest", $viewIcon = false)
4805  {
4806  $a = "";
4807  $latest = ($docrev == "latest" || $docrev == "");
4808  if ($htmllink) {
4809 
4810  if (!$title) $title = $this->getHTMLTitle(strtok($id, '#') , '', $latest);
4811  if (trim($title) == "") {
4812  if ($id < 0) {
4813  $a = "<a>" . sprintf(_("document not exists yet")) . "</a>";
4814  } else {
4815  $a = "<a>" . sprintf(_("unknown document id %s") , $id) . "</a>";
4816  }
4817  } else {
4818  $ul = getParam("CORE_STANDURL");
4819  if ($target == "mail") {
4820  $ul = GetParam("CORE_EXTERNURL") . "?";
4821  }
4822  if ($target == "ext") {
4823  //$ec=getSessionValue("ext:targetRelation");
4824  $jslatest = ($latest) ? 'true' : 'false';
4825  $ec = getHttpVars("ext:targetRelation", 'Ext.fdl.Document.prototype.publish("opendocument",null,%V%,"view",{latest:' . $jslatest . '})');
4826  if ($ec) {
4827  if (!is_numeric($id)) $id = getIdFromName($this->dbaccess, $id);
4828  else if ($latest) {
4829  $lid = getLatestDocId($this->dbaccess, $id);
4830  if ($lid) $id = $lid;
4831  }
4832  $ec = str_replace("%V%", $id, $ec);
4833  $ecu = str_replace("'", '"', $ec);
4834  $ajs = "";
4835  if ($viewIcon) {
4836  simpleQuery($this->dbaccess, sprintf('select icon from docread where id=%d', $id) , $iconValue, true, true);
4837  $ajs.= sprintf('class="relation" style="background-image:url(%s)"', $this->getIcon($iconValue, 14)) . $title;
4838  }
4839  $a = "<a $ajs onclick='parent.$ecu'>$title</a>";
4840  } else {
4841  if ($docrev == "latest" || $docrev == "" || !$docrev) $ul.= "&latest=Y";
4842  elseif ($docrev != "fixed") {
4843  // validate that docrev looks like state(xxx)
4844  if (preg_match("/^state\(([a-zA-Z0-9_:-]+)\)/", $docrev, $matches)) {
4845  $ul.= "&state=" . $matches[1];
4846  }
4847  }
4848  $ul.= "&app=FDL&action=VIEWEXTDOC&id=$id";
4849  $a = "<a href=\"$ul\">$title</a>";
4850  }
4851  } else {
4852  if ($docrev == "latest" || $docrev == "" || !$docrev) $ul.= "&latest=Y";
4853  elseif ($docrev != "fixed") {
4854  // validate that docrev looks like state(xxx)
4855  if (preg_match("/^state\(([a-zA-Z0-9_:-]+)\)/", $docrev, $matches)) {
4856  $ul.= "&state=" . $matches[1];
4857  }
4858  }
4859  $ul.= "&app=FDL&action=FDL_CARD&id=$id";
4860  if ($js) $ajs = "oncontextmenu=\"popdoc(event,'$ul');return false;\"";
4861  else $ajs = "";
4862 
4863  $ajs.= sprintf(' documentId="%s" ', $id);
4864  if ($viewIcon) {
4865  simpleQuery($this->dbaccess, sprintf('select icon from docread where id=%d', $id) , $iconValue, true, true);
4866  $ajs.= sprintf('class="relation" style="background-image:url(%s)"', $this->getIcon($iconValue, 14)) . $title;
4867  }
4868  $a = "<a $ajs target=\"$target\" href=\"$ul\">$title</a>";
4869  }
4870  }
4871  } else {
4872  if (!$title) $a = $this->getHTMLTitle($id, '', $latest);
4873  else $a = $title;
4874  }
4875  return $a;
4876  }
4877  final private function rowattrReplace($s, $index)
4878  {
4879  if (substr($s, 0, 2) == "L_") return "[$s]";
4880  if (substr($s, 0, 2) == "V_") {
4881  $sl = substr(strtolower($s) , 2);
4882  $vis = $this->getAttribute($sl)->mvisibility;
4883 
4884  if (($vis == "H") || ($vis == "I") || ($vis == "O")) $v = "";
4885  else $v = $this->GetHtmlAttrValue($sl, "_self", 2, $index);
4886  } else {
4887  $sl = strtolower($s);
4888  if (!isset($this->$sl)) return "[$s]";
4889  $v = $this->getTValue($sl, "", $index);
4890  }
4891  return $v;
4892  }
4893 
4894  final public function getHtmlValue($oattr, $value, $target = "_self", $htmllink = true, $index = - 1, $entities = true, $abstract = false)
4895  {
4896  global $action;
4897 
4898  $aformat = $oattr->format;
4899  $atype = $oattr->type;
4900 
4901  if (($oattr->repeat) && ($index <= 0)) {
4902  $tvalues = explode("\n", $value);
4903  } else {
4904  $tvalues[$index] = $value;
4905  }
4906  $idocfamid = $oattr->format;
4907 
4908  $attrid = $oattr->id;
4909  foreach ($tvalues as $kvalue => $avalue) {
4910  $htmlval = "";
4911 
4912  switch ($atype) {
4913  case "idoc":
4914  $aformat = "";
4915  $value = $avalue;
4916  if ($value != "") {
4917  // printf("la ");
4918  $temp = base64_decode($value);
4919  $entete = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>";
4920  $xml = $entete;
4921  $xml.= $temp;
4922  $title = recup_argument_from_xml($xml, "title"); //in freedom_util.php
4923 
4924  }
4925  $attrid = $attrid . $index;
4926  $htmlval = "<form style=\"display:inline\"><INPUT id=\"_" . $attrid . "\" TYPE=\"hidden\" name=\"_" . $attrid . "\" value=\"" . $value . " \">";
4927  $htmlval.= "<a onclick=\"subwindow(400,400,'_$attrid','');viewidoc('_$attrid','$idocfamid')\" ";
4928  $htmlval.= "oncontextmenu=\"viewidoc_in_popdoc(event,'$attrid','_$attrid','$idocfamid');return false\">$title</a>";
4929  $htmlval.= "</form>";
4930  break;
4931 
4932  case "image":
4933  if ($target == "mail") {
4934  $htmlval = "cid:" . $oattr->id;
4935  if ($index >= 0) $htmlval.= "+$index";
4936  }
4937  if ($target == "te") {
4938  $htmlval = "file://" . $this->vault_filename($oattr->id, true, $kvalue);
4939  } else {
4940  $vid = "";
4941  if (preg_match(PREGEXPFILE, $avalue, $reg)) {
4942  $vid = $reg[2];
4943 
4944  if (($oattr->repeat) && ($index <= 0)) $idx = $kvalue;
4945  else $idx = $index;
4946  $inline = $oattr->getOption("inline");
4947  if ($inline == "yes") $opt = "&inline=yes";
4948  else $opt = "";
4949  $htmlval = $action->GetParam("CORE_BASEURL") . "app=FDL" . "&action=EXPORTFILE$opt&cache=no&vid=$vid&docid=" . $this->id . "&attrid=" . $oattr->id . "&index=$idx"; // upload name
4950 
4951  } else {
4952  $htmlval = $action->GetImageUrl($avalue);
4953  }
4954  }
4955  break;
4956 
4957  case "file":
4958  $vid = "";
4959  $info = false;
4960  if (preg_match(PREGEXPFILE, $avalue, $reg)) {
4961  // reg[1] is mime type
4962  $vid = $reg[2];
4963  $mime = $reg[1];
4964  include_once ("FDL/Lib.Dir.php");
4965  $vf = newFreeVaultFile($this->dbaccess);
4966  if ($vf->Show($reg[2], $info) == "") $fname = $info->name;
4967  else $htmlval = _("vault file error");
4968  } else $htmlval = _("no filename");
4969 
4970  if ($target == "mail") {
4971  $htmlval = "<a target=\"_blank\" href=\"";
4972  $htmlval.= "cid:" . $oattr->id;
4973  if ($index >= 0) $htmlval.= "+$index";
4974  $htmlval.= "\">" . $fname . "</a>";
4975  } else {
4976  if ($info) {
4977  if ($info->teng_state < 0 || $info->teng_state > 1) {
4978  $htmlval = "";
4979  include_once ("WHAT/Class.TEClient.php");
4980  switch (intval($info->teng_state)) {
4981  case TransformationEngine::error_convert: // convert fail
4982  $textval = _("file conversion failed");
4983  break;
4984 
4985  case TransformationEngine::error_noengine: // no compatible engine
4986  $textval = _("file conversion not supported");
4987  break;
4988 
4989  case TransformationEngine::error_connect: // no compatible engine
4990  $textval = _("cannot contact server");
4991  break;
4992 
4993  case TransformationEngine::status_waiting: // waiting
4994  $textval = _("waiting conversion file");
4995  break;
4996 
4997  case TransformationEngine::status_inprogress: // in progress
4998  $textval = _("generating file");
4999  break;
5000 
5001  default:
5002  $textval = sprintf(_("unknown file state %s") , $info->teng_state);
5003  }
5004  if ($htmllink) {
5005  //$errconvert=trim(file_get_contents($info->path));
5006  //$errconvert=sprintf('<p>%s</p>',str_replace(array("'","\r","\n"),array("&rsquo;",""),nl2br(htmlspecialchars($errconvert,ENT_COMPAT,"UTF-8"))));
5007  if ($info->teng_state > 1) $waiting = "<img class=\"mime\" src=\"Images/loading.gif\">";
5008  else $waiting = "<img class=\"mime\" needresize=1 src=\"Images/bullet_error.png\">";;
5009  $htmlval = sprintf('<a _href_="%s" vid="%d" onclick="popdoc(event,this.getAttribute(\'_href_\')+\'&inline=yes\',\'%s\')">%s %s</a>', $this->getFileLink($oattr->id, $index) , $info->id_file, str_replace("'", "&rsquo;", _("file status")) , $waiting, $textval);
5010  if ($info->teng_state < 0) {
5011  $htmlval.= sprintf('<a href="?app=FDL&action=FDL_METHOD&id=%d&method=resetConvertVaultFile(\'%s,%s)"><img class="mime" title="%s" src="%s"></a>', $this->id, $oattr->id, $index, _("retry file conversion") , "Images/arrow_refresh.png");
5012  }
5013  } else {
5014  $htmlval = $textval;
5015  }
5016  } elseif ($htmllink) {
5017 
5018  $mimeicon = getIconMimeFile($info->mime_s == "" ? $mime : $info->mime_s);
5019  if (($oattr->repeat) && ($index <= 0)) $idx = $kvalue;
5020  else $idx = $index;
5021  $standardview = true;
5022  $infopdf = false;
5023  $viewfiletype = $oattr->getOption("viewfiletype");
5024  if ($viewfiletype == "image" || $viewfiletype == "pdf") {
5025  global $action;
5026  $waiting = false;
5027  if (substr($info->mime_s, 0, 5) == "image") {
5028  $imageview = true;
5029  $viewfiletype = 'png';
5030  $pages = 1;
5031  } elseif (substr($info->mime_s, 0, 4) == "text") {
5032  $imageview = true;
5033  $viewfiletype = 'embed';
5034  $pages = 1;
5035  } else {
5036  $err = $vf->Show($vid, $infopdf, 'pdf');
5037  if ($err == "") {
5038  if ($infopdf->teng_state == TransformationEngine::status_done || $infopdf->teng_state == TransformationEngine::status_waiting || $infopdf->teng_state == TransformationEngine::status_inprogress) {
5039  $imageview = true;
5040  if ($viewfiletype == 'image') $viewfiletype = 'png';
5041  else if ($viewfiletype == 'pdf') $viewfiletype = 'embed';
5042 
5043  $pages = getPdfNumberOfPages($infopdf->path);
5044  if ($infopdf->teng_state == TransformationEngine::status_waiting || $infopdf->teng_state == TransformationEngine::status_inprogress) $waiting = true;
5045  }
5046  }
5047  }
5048 
5049  if ($imageview && (!$abstract)) {
5050  $action->parent->AddJsRef($action->GetParam("CORE_JSURL") . "/widgetFile.js");
5051  $action->parent->AddJsRef($action->GetParam("CORE_JSURL") . "/detectPdfPlugin.js");
5052  $lay = new Layout("FDL/Layout/viewfileimage.xml", $action);
5053  $lay->set("docid", $this->id);
5054  $lay->set("waiting", ($waiting ? 'true' : 'false'));
5055  $lay->set("attrid", $oattr->id);
5056  $lay->set("index", $idx);
5057  $lay->set("viewtype", $viewfiletype);
5058  $lay->set("mimeicon", $mimeicon);
5059  $lay->set("vid", ($infopdf ? $infopdf->id_file : $vid));
5060  $lay->set("filetitle", $fname);
5061  $lay->set("height", $oattr->getOption('viewfileheight', '300px'));
5062  $lay->set("filelink", $this->getFileLink($oattr->id, $idx, false, false));
5063 
5064  $lay->set("pdflink", '');
5065  if ($pdfattr = $oattr->getOption('pdffile')) {
5066  //$infopdf=$this->vault_properties($this->getAttribute($pdfattr));
5067  if (!preg_match('/^(text|image)/', $info->mime_s)) {
5068  //$pdfidx=($idx <0)?0:$idx;
5069  if ($waiting || preg_match('/(pdf)/', $infopdf->mime_s)) {
5070  $lay->set("pdflink", $this->getFileLink($pdfattr, $idx, false, false));
5071  }
5072  }
5073  }
5074  $lay->set("pages", $pages); // todo
5075  $htmlval = $lay->gen();
5076  $standardview = false;
5077  }
5078  }
5079  if ($standardview) {
5080  $size = round($info->size / 1024) . _("AbbrKbyte");
5081  $utarget = ($action->Read("navigator", "") == "NETSCAPE") ? "_self" : "_blank";
5082  $opt = "";
5083  $inline = $oattr->getOption("inline");
5084  if ($inline == "yes") $opt = "&inline=yes";
5085  $htmlval = "<a onmousedown=\"document.noselect=true;\" title=\"$size\" target=\"$utarget\" type=\"$mime\" href=\"" . $this->getFileLink($oattr->id, $idx, false, ($inline == "yes")) . "\">";
5086  if ($mimeicon) $htmlval.= "<img class=\"mime\" needresize=1 src=\"Images/$mimeicon\">&nbsp;";
5087  $htmlval.= $fname . "</a>";
5088  }
5089  } else {
5090  $htmlval = $info->name;
5091  }
5092  }
5093  }
5094 
5095  break;
5096 
5097  case "longtext":
5098  case "xml":
5099  if ($entities) $bvalue = nl2br(htmlentities(stripslashes(str_replace("<BR>", "\n", $avalue)) , ENT_COMPAT, "UTF-8"));
5100  else $bvalue = stripslashes(str_replace("<BR>", "\n", $avalue));
5101  $shtmllink = $htmllink ? "true" : "false";
5102  $bvalue = preg_replace("/(\[|&#x5B;)ADOC ([^\]]*)\]/e", "\$this->getDocAnchor('\\2',\"$target\",$shtmllink)", $bvalue);
5103  $htmlval = str_replace(array(
5104  "[",
5105  "$"
5106  ) , array(
5107  "&#091;",
5108  "&#036;"
5109  ) , $bvalue);
5110  break;
5111 
5112  case "password":
5113  $htmlval = preg_replace("/./", "*", htmlentities(stripslashes($avalue) , ENT_COMPAT, "UTF-8"));
5114 
5115  break;
5116 
5117  case "enum":
5118  $enumlabel = $oattr->getEnumlabel();
5119  $colors = $oattr->getOption("boolcolor");
5120  if ($colors != "") {
5121  if (isset($enumlabel[$avalue])) {
5122  reset($enumlabel);
5123  $tcolor = explode(",", $colors);
5124  if (current($enumlabel) == $enumlabel[$avalue]) {
5125  $color = $tcolor[0];
5126  $htmlval = sprintf('<pre style="background-color:%s;display:inline">&nbsp;-&nbsp;</pre>', $color);
5127  } else {
5128  $color = $tcolor[1];
5129  $htmlval = sprintf('<pre style="background-color:%s;display:inline">&nbsp;&bull;&nbsp;</pre>', $color);
5130  }
5131  } else $htmlval = $avalue;
5132  } else {
5133  if (isset($enumlabel[$avalue])) $htmlval = $enumlabel[$avalue];
5134  else $htmlval = $avalue;
5135  }
5136 
5137  break;
5138 
5139  case "array":
5140  $viewzone = $oattr->getOption("rowviewzone");
5141  $sort = $oattr->getOption("sorttable");
5142  if ($sort == "yes") {
5143  global $action;
5144  $action->parent->AddJsRef($action->GetParam("CORE_PUBURL") . "/FREEDOM/Layout/sorttable.js");
5145  }
5146 
5147  $lay = new Layout("FDL/Layout/viewdocarray.xml", $action);
5148  $lay->set("issort", ($sort == "yes"));
5149  if (!method_exists($this->attributes, "getArrayElements")) {
5150  break;
5151  }
5152  $height = $oattr->getOption("height", false);
5153  $lay->set("tableheight", $height);
5154  $caption = '';
5155  if (($oattr->getOption("vlabel", "up") == "up")) $caption = $oattr->getLabel();
5156  $lay->set("caption", $caption);
5157  $lay->set("aid", $oattr->id);
5158 
5159  if (($viewzone != "") && preg_match("/([A-Z_-]+):([^:]+):{0,1}[A-Z]{0,1}/", $viewzone, $reg)) {
5160  // detect special row zone
5161  $dxml = new DomDocument();
5162  $rowlayfile = getLayoutFile($reg[1], ($reg[2]));
5163  if (!@$dxml->load($rowlayfile)) {
5164  AddwarningMsg(sprintf(_("cannot open %s layout file") , DEFAULT_PUBDIR . "/$rowlayfile"));
5165  break;
5166  }
5167  $theads = $dxml->getElementsByTagName('table-head');
5168  if ($theads->length > 0) {
5169  $thead = $theads->item(0);
5170  $theadcells = $thead->getElementsByTagName('cell');
5171  $talabel = array();
5172  for ($i = 0; $i < $theadcells->length; $i++) {
5173  $th = xt_innerXML($theadcells->item($i));
5174  $thstyle = $theadcells->item($i)->getAttribute("style");
5175  if ($thstyle != "") $thstyle = "style=\"$thstyle\"";
5176  $talabel[] = array(
5177  "alabel" => $th,
5178  "astyle" => $thstyle,
5179  "cwidth" => "auto"
5180  );
5181  }
5182  $lay->setBlockData("TATTR", $talabel);
5183  }
5184 
5185  $tbodies = $dxml->getElementsByTagName('table-body');
5186  if ($tbodies->length > 0) {
5187  $tbody = $tbodies->item(0);
5188  $tbodycells = $tbody->getElementsByTagName('cell');
5189  for ($i = 0; $i < $tbodycells->length; $i++) {
5190  $tr[] = xt_innerXML($tbodycells->item($i));
5191  $tcellstyle[] = $tbodycells->item($i)->getAttribute("style");
5192  }
5193  }
5194  $ta = $this->attributes->getArrayElements($oattr->id);
5195  $nbitem = 0;
5196  foreach ($ta as $k => $v) {
5197  $tval[$k] = $this->getTValue($k);
5198  $nbitem = max($nbitem, count($tval[$k]));
5199  if ($emptyarray && ($this->getValue($k) != "")) $emptyarray = false;
5200  $lay->set("L_" . strtoupper($v->id) , mb_ucfirst($v->getLabel()));
5201  }
5202  // view values
5203  $tvattr = array();
5204  for ($k = 0; $k < $nbitem; $k++) {
5205  $tvattr[] = array(
5206  "bevalue" => "bevalue_$k"
5207  );
5208  reset($ta);
5209  $tivalue = array();
5210 
5211  foreach ($tr as $kd => $vd) {
5212 
5213  $hval = preg_replace("/\[([^\]]*)\]/e", "\$this->rowattrReplace('\\1',$k)", $vd);
5214  $tdstyle = $tcellstyle[$kd];
5215  $tivalue[] = array(
5216  "evalue" => $hval,
5217  "color" => "inherit",
5218  "tdstyle" => $tdstyle,
5219  "bgcolor" => "inherit",
5220  "align" => "inherit"
5221  );
5222  }
5223  $lay->setBlockData("bevalue_$k", $tivalue);
5224  }
5225  $lay->setBlockData("EATTR", $tvattr);
5226  if ($nbitem > 10) $lay->set("caption", $oattr->getLabel() . " ($nbitem)");
5227 
5228  $htmlval = $lay->gen();
5229  } else {
5230  $ta = $this->attributes->getArrayElements($oattr->id);
5231  $talabel = array();
5232  $tvattr = array();
5233 
5234  $emptyarray = true;
5235  $nbitem = 0;
5236  foreach ($ta as $k => $v) {
5237  if (($v->mvisibility == "H") || ($v->mvisibility == "I") || ($v->mvisibility == "O")) continue;
5238  $talabel[] = array(
5239  "alabel" => mb_ucfirst($v->getLabel()) ,
5240  "astyle" => $v->getOption("cellheadstyle") ,
5241  "cwidth" => $v->getOption("cwidth", "auto")
5242  );
5243  $tval[$k] = $this->getTValue($k);
5244  $nbitem = max($nbitem, count($tval[$k]));
5245  if ($emptyarray && ($this->getValue($k) != "")) $emptyarray = false;
5246  }
5247  if (!$emptyarray) {
5248  if ($oattr->getOption("vlabel") == "up") {
5249  $caption = $oattr->getLabel();
5250  if ($nbitem > 10) $caption.= " ($nbitem)";
5251  } else {
5252  $caption = "";
5253  if ($nbitem > 10) {
5254  if (count($talabel) > 0) {
5255  $talabel[0]["alabel"].= " ($nbitem)";
5256  }
5257  }
5258  }
5259 
5260  $lay->setBlockData("TATTR", $talabel);
5261  $lay->set("caption", $caption);
5262  $tvattr = array();
5263  for ($k = 0; $k < $nbitem; $k++) {
5264  $tvattr[] = array(
5265  "bevalue" => "bevalue_$k"
5266  );
5267  $tivalue = array();
5268  foreach ($ta as $ka => $va) {
5269  if (($va->mvisibility == "H") || ($va->mvisibility == "I") || ($va->mvisibility == "O")) continue;
5270  $hval = $this->getHtmlValue($va, $tval[$ka][$k], $target, $htmllink, $k);
5271  if ($va->type == "image") {
5272  $iwidth = $va->getOption("iwidth", "80px");
5273  if ($tval[$ka][$k] == "") $hval = "";
5274  else if ($va->link == "") {
5275  if (strstr($hval, '?')) $optwidth = "&width=" . intval($iwidth);
5276  else $optwidth = '';
5277  $hval = "<a href=\"$hval\"><img border='0' width=\"$iwidth\" src=\"" . $hval . $optwidth . "\"></a>";
5278  } else {
5279  $hval = preg_replace("/>(.+)</", ">&nbsp;<img class=\"button\" width=\"$iwidth\" src=\"\\1\">&nbsp;<", $hval);
5280  }
5281  }
5282  $tivalue[] = array(
5283  "evalue" => $hval,
5284  "tdstyle" => $va->getOption("cellbodystyle") ,
5285  "color" => $va->getOption("color", "inherit") ,
5286  "bgcolor" => $va->getOption("bgcolor", "inherit") ,
5287  "align" => $va->getOption("align", "inherit")
5288  );
5289  }
5290  $lay->setBlockData("bevalue_$k", $tivalue);
5291  }
5292  $lay->setBlockData("EATTR", $tvattr);
5293 
5294  $htmlval = $lay->gen();
5295  } else {
5296  $htmlval = "";
5297  }
5298  }
5299  break;
5300 
5301  case "doc":
5302 
5303  $htmlval = "";
5304  if ($avalue != "") {
5305  if ($kvalue > - 1) $idocid = $this->getTValue($aformat, "", $kvalue);
5306  else $idocid = $this->getValue($aformat);
5307 
5308  if ($idocid > 0) {
5309  //$lay = new Layout("FDL/Layout/viewadoc.xml", $action);
5310  //$lay->set("id",$idocid);
5311  $idoc = new_Doc($this->dbaccess, $idocid);
5312  $htmlval = $idoc->viewDoc("FDL:VIEWTHUMBCARD:T", "finfo");
5313  //$htmlval =$lay->gen();
5314 
5315  }
5316  }
5317  break;
5318 
5319  case "docid":
5320  if ($oattr->format != "") {
5321 
5322  $aformat = "";
5323  $multiple = ($oattr->getOption("multiple") == "yes");
5324  $dtarget = $target;
5325  if ($target != "mail") {
5326  $ltarget = $oattr->getOption("ltarget");
5327  if ($ltarget != "") $dtarget = $ltarget;
5328  }
5329  if ($multiple) {
5330  $avalue = str_replace("\n", "<BR>", $avalue);
5331  $tval = explode("<BR>", $avalue);
5332  $thval = array();
5333  foreach ($tval as $kv => $vv) {
5334  if (trim($vv) == "") $thval[] = $vv;
5335  elseif ($oattr->link != "") {
5336  $link = preg_replace("/%" . $oattr->id . "%/i", $vv, $oattr->link);
5337  $link = $this->urlWhatEncode($oattr->link, $kvalue);
5338  if ($link) $thval[] = '<a target="' . $dtarget . '" href="' . $link . '">' . $this->getHTMLTitle($vv) . '</a>';
5339  else $thval[] = $this->getHTMLTitle($vv);
5340  } else $thval[] = $this->getDocAnchor(trim($vv) , $dtarget, $htmllink, false, true, $oattr->getOption("docrev") , true);
5341  }
5342  if ($oattr->link) $htmllink = false;
5343  $htmlval = implode("<br/>", $thval);
5344  } else {
5345  if ($avalue == "") $htmlval = $avalue;
5346  elseif ($oattr->link != "") $htmlval = $this->getHTMLTitle($avalue);
5347  else $htmlval = $this->getDocAnchor(trim($avalue) , $dtarget, $htmllink, false, true, $oattr->getOption("docrev") , true);
5348  }
5349  } else $htmlval = $avalue;
5350 
5351  break;
5352 
5353  case "thesaurus":
5354  $aformat = "";
5355  $multiple = ($oattr->getOption("multiple") == "yes");
5356  if ($multiple) {
5357  $avalue = str_replace("\n", "<BR>", $avalue);
5358  $tval = explode("<BR>", $avalue);
5359  $thval = array();
5360  foreach ($tval as $kv => $vv) {
5361  if (trim($vv) == "") $thval[] = $vv;
5362  else {
5363  $thc = new_doc($this->dbaccess, trim($vv));
5364  if ($thc->isAlive()) $thval[] = $this->getDocAnchor(trim($vv) , $target, $htmllink, $thc->getLangTitle());
5365  else $thval[] = "th error $vv";
5366  }
5367  }
5368  $htmlval = implode("<br/>", $thval);
5369  } else {
5370  if ($avalue == "") $htmlval = $avalue;
5371  else {
5372  $thc = new_doc($this->dbaccess, $avalue);
5373  if ($thc->isAlive()) $htmlval = $this->getDocAnchor(trim($avalue) , $target, $htmllink, $thc->getLangTitle());
5374  else $htmlval = "th error $avalue";
5375  }
5376  }
5377 
5378  break;
5379 
5380  case "option":
5381  $lay = new Layout("FDL/Layout/viewdocoption.xml", $action);
5382  $htmlval = "";
5383 
5384  if ($kvalue > - 1) $di = $this->getTValue($oattr->format, "", $kvalue);
5385  else $di = $this->getValue($oattr->format);
5386  if ($di > 0) {
5387  $lay->set("said", $di);
5388  $lay->set("uuvalue", urlencode($avalue));
5389 
5390  $htmlval = $lay->gen();
5391  }
5392  break;
5393 
5394  case 'money':
5395 
5396  if ($avalue !== '') {
5397  $htmlval = money_format('%!.2n', doubleval($avalue));
5398  $htmlval = str_replace(" ", "&nbsp;", $htmlval); // need to replace space by non breaking spaces
5399 
5400  } else {
5401  $htmlval = '';
5402  }
5403  break;
5404 
5405  case 'htmltext':
5406  $shtmllink = $htmllink ? "true" : "false";
5407  $avalue = preg_replace("/(\[|&#x5B;)ADOC ([^\]]*)\]/e", "\$this->getDocAnchor('\\2',\"$target\",$shtmllink)", $avalue);
5408  $htmlval = '<div class="htmltext">' . $avalue . '</div>';
5409  break;
5410 
5411  case 'date':
5412  if (($aformat != "") && (trim($avalue) != "")) {
5413  if ($avalue) $htmlval = strftime($aformat, stringDateToUnixTs($avalue));
5414  else $htmlval = $avalue;
5415  } elseif (trim($avalue) == "") {
5416  $htmlval = "";
5417  } else {
5418 
5419  $htmlval = stringDateToLocaleDate($avalue);
5420  }
5421  $aformat = "";
5422  break;
5423 
5424  case 'time':
5425  if (($aformat != "") && (trim($avalue) != "")) {
5426  if ($avalue) $htmlval = strftime($aformat, strtotime($avalue));
5427  else $htmlval = $avalue;
5428  } else {
5429  $htmlval = substr($avalue, 0, 5); // do not display second
5430 
5431  }
5432  $aformat = "";
5433  break;
5434 
5435  case 'timestamp':
5436  if (($aformat != "") && (trim($avalue) != "")) {
5437  if ($avalue) $htmlval = strftime($aformat, stringDateToUnixTs($avalue));
5438  else $htmlval = $avalue;
5439  } elseif (trim($avalue) == "") {
5440  $htmlval = "";
5441  } else {
5442  $htmlval = stringDateToLocaleDate($avalue);
5443  }
5444  $aformat = "";
5445  break;
5446 
5447  case 'ifile':
5448  $lay = new Layout("FDL/Layout/viewifile.xml", $action);
5449  $lay->set("aid", $oattr->id);
5450  $lay->set("id", $this->id);
5451  $lay->set("iheight", $oattr->getOption("height", "200px"));
5452  $htmlval = $lay->gen();
5453 
5454  break;
5455 
5456  case 'color':
5457  $htmlval = sprintf("<span style=\"background-color:%s\">%s</span>", $avalue, $avalue);
5458  break;
5459 
5460  default:
5461  if ($entities) $avalue = htmlentities(stripslashes($avalue) , ENT_COMPAT, "UTF-8");
5462  else $avalue = stripslashes($avalue);
5463  $htmlval = str_replace(array(
5464  "[",
5465  "$"
5466  ) , array(
5467  "&#091;",
5468  "&#036;"
5469  ) , $avalue);
5470 
5471  break;
5472  }
5473 
5474  if (($htmlval !== '') && ($aformat != "") && ($atype != "doc") && ($atype != "array") && ($atype != "option")) {
5475  //printf($htmlval);
5476  $htmlval = sprintf($aformat, $htmlval);
5477  }
5478  // add link if needed
5479  if ($htmllink && ($oattr->link != "")) {
5480  $ititle = "";
5481  $hlink = $oattr->link;
5482  if ($hlink[0] == "[") {
5483  if (preg_match('/\[(.*)\](.*)/', $hlink, $reg)) {
5484  $hlink = $reg[2];
5485  $ititle = str_replace("\"", "'", $reg[1]);
5486  }
5487  }
5488  if ($ulink = $this->urlWhatEncode($hlink, $kvalue)) {
5489  if ($target == "ext") {
5490  if (preg_match("/FDL_CARD.*id=([0-9]+)/", $ulink, $reg)) {
5491  $abegin = $this->getDocAnchor($reg[1], $target, true, $htmlval);
5492  $htmlval = '';
5493  $aend = "";
5494  } else if (true || preg_match("/^http:/", $ulink, $reg)) {
5495  $ec = getSessionValue("ext:targetUrl");
5496 
5497  if ($ec) {
5498  $ec = str_replace("%V%", $ulink, $ec);
5499  $ec = str_replace("%L%", $oattr->getLabel() , $ec);
5500  $ecu = str_replace("'", "\\'", $this->urlWhatEncode($ec));
5501  $abegin = "<a onclick='parent.$ecu'>";
5502  } else {
5503  $ltarget = $oattr->getOption("ltarget");
5504  $abegin = "<a target=\"$ltarget\" href=\"$ulink\">";
5505  }
5506 
5507  $aend = "</a>";
5508  }
5509  } else if ($target == "mail") {
5510  $scheme = "";
5511  if (preg_match("/^([[:alpha:]]*):(.*)/", $ulink, $reg)) {
5512  $scheme = $reg[1];
5513  }
5514  $abegin = "<a target=\"$target\" href=\"";
5515  if ($scheme == "") $abegin.= $action->GetParam("CORE_URLINDEX", ($action->GetParam("CORE_ABSURL") . "/")) . $ulink;
5516  else $abegin.= $ulink;
5517  $abegin.= "\">";
5518  $aend = "</a>";
5519  } else {
5520  $ltarget = $oattr->getOption("ltarget");
5521  if ($ltarget != "") $target = $ltarget;
5522  $ltitle = $oattr->getOption("ltitle");
5523  if ($ltitle != "") $ititle = str_replace("\"", "'", $ltitle);
5524  $abegin = "<a target=\"$target\" title=\"$ititle\" onmousedown=\"document.noselect=true;\" href=\"";
5525  $abegin.= $ulink . "\" ";;
5526  if ($htmllink > 1) {
5527  $scheme = "";
5528  if (preg_match("/^([[:alpha:]]*):(.*)/", $ulink, $reg)) {
5529  $scheme = $reg[1];
5530  }
5531  if (($scheme == "") || ($scheme == "http")) {
5532  if ($scheme == "") $ulink.= "&ulink=1";
5533  $abegin.= " oncontextmenu=\"popdoc(event,'$ulink');return false;\" ";
5534  }
5535  }
5536  $abegin.= ">";
5537  $aend = "</a>";
5538  }
5539  } else {
5540  $abegin = "";
5541  $aend = "";
5542  }
5543  } else {
5544  $abegin = "";
5545  $aend = "";
5546  }
5547 
5548  $thtmlval[$kvalue] = $abegin . $htmlval . $aend;
5549  }
5550 
5551  return implode("<BR>", $thtmlval);
5552  }
5553  /**
5554  * return raw content
5555  * @param string $attr html tag attributes
5556  * @param string $data html content (innerHTML)
5557  * @return string raw content
5558  */
5559  final private static function getHtmlTdContent($attr, $data)
5560  {
5561  $data = preg_replace('|<(/?[^> ]+)(\s[^>]*?)?>|ms', '', $data); // delete all tags
5562  return '<td>' . $data . '</td>';
5563  }
5564 
5565  final public function getHtmlAttrValue($attrid, $target = "_self", $htmllink = 2, $index = - 1, $entities = true, $abstract = false)
5566  {
5567  if ($index != - 1) $v = $this->getTValue($attrid, "", $index);
5568  else $v = $this->getValue($attrid);
5569  if ($v == "") return $v;
5570  return $this->GetHtmlValue($this->getAttribute($attrid) , $v, $target, $htmllink, $index, $entities, $abstract);
5571  }
5572  /**
5573  * Get a textual representation of the content of an attribute
5574  *
5575  * @param string $attrId logical name of the attr
5576  * @param array $configuration value config array : dateFormat => 'US' 'ISO', decimalSeparator => '.',
5577  * multipleSeparator => array(0 => 'arrayLine', 1 => 'multiple') (defaultValue : dateFormat : 'US', decimalSeparator : '.', multiple => array(0 => "\n", 1 => ", "))
5578  *
5579  * @return string|BOOLEAN
5580  *
5581  */
5582  final public function getTextualAttrValue($attrId, $index = - 1, Array $configuration = array())
5583  {
5584  $objectAttr = $this->getAttribute($attrId);
5585  if ($objectAttr) {
5586  return $objectAttr->getTextualValue($this, $index, $configuration);
5587  } else {
5588  return $objectAttr;
5589  }
5590  }
5591 
5592  final public function getOooAttrValue($attrid, $target = "_self", $htmllink = false, $index = - 1)
5593  {
5594  if ($index != - 1) $v = $this->getTValue($attrid, "", $index);
5595  else $v = $this->getValue($attrid);
5596  if ($v == "") return $v;
5597  return $this->getOooValue($this->getAttribute($attrid) , $v, $target, $htmllink, $index);
5598  }
5599  final public function getOooValue($oattr, $value, $target = "_self", $htmllink = false, $index = - 1)
5600  {
5601  global $action;
5602 
5603  $aformat = $oattr->format;
5604  $atype = $oattr->type;
5605 
5606  if (($oattr->repeat) && ($index <= 0)) {
5607  $tvalues = explode("\n", $value);
5608  } else {
5609  $tvalues[$index] = $value;
5610  }
5611  $idocfamid = $oattr->format;
5612 
5613  $attrid = $oattr->id;
5614  foreach ($tvalues as $kvalue => $avalue) {
5615  $htmlval = "";
5616  switch ($atype) {
5617  case "idoc":
5618  // nothing
5619  break;
5620 
5621  case "image":
5622  $htmlval = $this->vault_filename_fromvalue($avalue, true);
5623  break;
5624 
5625  case "file":
5626  // file name
5627  $htmlval = $this->vault_filename_fromvalue($avalue, false);
5628  break;
5629 
5630  case "longtext":
5631  case "xml":
5632  $htmlval = str_replace("&", "&amp;", $avalue);
5633  $htmlval = str_replace(array(
5634  "<",
5635  ">"
5636  ) , array(
5637  "&lt;",
5638  "&gt;"
5639  ) , $htmlval);
5640  $htmlval = str_replace("\n", "<text:line-break/>", $htmlval);
5641  $htmlval = str_replace("&lt;BR&gt;", "<text:line-break/>", $htmlval);
5642  $htmlval = str_replace("\r", "", $htmlval);
5643  break;
5644 
5645  case "password":
5646 
5647  break;
5648 
5649  case "enum":
5650  $enumlabel = $oattr->getEnumlabel();
5651  $colors = $oattr->getOption("boolcolor");
5652  if ($colors != "") {
5653  if (isset($enumlabel[$avalue])) {
5654  reset($enumlabel);
5655  $tcolor = explode(",", $colors);
5656  if (current($enumlabel) == $enumlabel[$avalue]) {
5657  $color = $tcolor[0];
5658  $htmlval = sprintf('<pre style="background-color:%s;display:inline">&nbsp;-&nbsp;</pre>', $color);
5659  } else {
5660  $color = $tcolor[1];
5661  $htmlval = sprintf('<pre style="background-color:%s;display:inline">&nbsp;&bull;&nbsp;</pre>', $color);
5662  }
5663  } else $htmlval = $avalue;
5664  } else {
5665  if (isset($enumlabel[$avalue])) $htmlval = $enumlabel[$avalue];
5666  else $htmlval = $avalue;
5667  }
5668 
5669  break;
5670 
5671  case "thesaurus":
5672  $aformat = "";
5673  $multiple = ($oattr->getOption("multiple") == "yes");
5674  if ($multiple) {
5675  $avalue = str_replace("\n", "<BR>", $avalue);
5676  $tval = explode("<BR>", $avalue);
5677  $thval = array();
5678  foreach ($tval as $kv => $vv) {
5679  if (trim($vv) == "") $thval[] = $vv;
5680  else {
5681  $thc = new_doc($this->dbaccess, trim($vv));
5682  if ($thc->isAlive()) $thval[] = $thc->getLangTitle();
5683  else $thval[] = "th error $vv";
5684  }
5685  }
5686  $htmlval = implode("<text:tab/>", $thval);
5687  } else {
5688  if ($avalue == "") $htmlval = $avalue;
5689  else {
5690  $thc = new_doc($this->dbaccess, $avalue);
5691  if ($thc->isAlive()) $htmlval = $thc->getLangTitle();
5692  else $htmlval = "th error $avalue";
5693  }
5694  }
5695 
5696  break;
5697 
5698  case "array":
5699  break;
5700 
5701  case "doc":
5702  break;
5703 
5704  case "docid":
5705  if ($oattr->format != "") {
5706 
5707  $aformat = "";
5708  $multiple = ($oattr->getOption("multiple") == "yes");
5709  $dtarget = $target;
5710  if ($target != "mail") {
5711  $ltarget = $oattr->getOption("ltarget");
5712  if ($ltarget != "") $dtarget = $ltarget;
5713  }
5714  if ($multiple) {
5715  $avalue = str_replace("\n", "<BR>", $avalue);
5716  $tval = explode("<BR>", $avalue);
5717  $thval = array();
5718  foreach ($tval as $kv => $vv) {
5719  if (trim($vv) == "") $thval[] = $vv;
5720  else $thval[] = $this->getDocAnchor(trim($vv) , $dtarget, false);
5721  }
5722  $htmlval = implode("<text:tab/>", $thval);
5723  } else {
5724  if ($avalue == "") $htmlval = $avalue;
5725  elseif ($oattr->link != "") $htmlval = $this->getTitle($avalue);
5726  else $htmlval = $this->getDocAnchor(trim($avalue) , $dtarget, false);
5727  }
5728  } else $htmlval = $avalue;
5729 
5730  break;
5731 
5732  case "option":
5733  break;
5734 
5735  case "money":
5736  $htmlval = money_format('%!.2n', doubleval($avalue));
5737  //$htmlval=str_replace(" ","&nbsp;",$htmlval); // need to replace space by non breaking spaces
5738  break;
5739 
5740  case "htmltext":
5741  $html_body = trim($avalue);
5742  $html_body = str_replace(array(
5743  '&quot;',
5744  '&lt;',
5745  '&gt;'
5746  ) , array(
5747  '--quoteric--',
5748  '--lteric--',
5749  '--gteric--'
5750  ) , $html_body); // prevent pb for quot in quot
5751  if ($html_body[0] != '<') {
5752  // think it is raw text
5753  $html_body = str_replace("\n<br/>", "\n", $html_body);
5754  $html_body = str_replace('<br/>', "\n", $html_body);
5755  if (!strpos($html_body, '<br')) $html_body = str_replace(array(
5756  "<",
5757  ">",
5758  '&'
5759  ) , array(
5760  "&lt;",
5761  "&gt;",
5762  "&amp;"
5763  ) , $html_body);
5764  $html_body = '<p>' . nl2br($html_body) . '</p>';
5765  }
5766  $html_body = str_replace(">\r\n", ">", $html_body);
5767  $html_body = str_replace("\r", "", $html_body);
5768 
5769  $html_body = preg_replace("/<!--.*?-->/ms", "", $html_body); //delete comments
5770  $html_body = preg_replace("/<td(\s[^>]*?)?>(.*?)<\/td>/mse", "\$this->getHtmlTdContent('\\1','\\2')", $html_body); // accept only text in td tag
5771  $html_body = cleanhtml($html_body);
5772  $html_body = preg_replace("/(<\/?)([^\s>]+)([^>]*)(>)/e", "toxhtmltag('\\1','\\2','\\3','\\4')", $html_body); // begin tag transform to pseudo xhtml
5773  $html_body = str_replace(array(
5774  '\"',
5775  '&quot;'
5776  ) , '"', $html_body);
5777  $html_body = str_replace('&', '&amp;', html_entity_decode($html_body, ENT_NOQUOTES, 'UTF-8'));
5778 
5779  $html_body = str_replace(array(
5780  '--quoteric--',
5781  '--lteric--',
5782  '--gteric--'
5783  ) , array(
5784  '&quot;',
5785  '&lt;',
5786  '&gt;'
5787  ) , $html_body); // prevent pb for quot in quot
5788  $xmldata = '<xhtml:body xmlns:xhtml="http://www.w3.org/1999/xhtml">' . $html_body . "</xhtml:body>";
5789 
5790  $xslt = new xsltProcessor;
5791  $xslt->importStyleSheet(DomDocument::load(DEFAULT_PUBDIR . "/CORE/Layout/html2odt.xsl"));
5792  // set_error_handler('HandleXmlError');
5793  try {
5794  $dom = @DomDocument::loadXML($xmldata);
5795  }
5796  catch(Exception $e) {
5797  addWarningMsg(sprintf(_("possible incorrect conversion HTML to ODT %s") , $this->title));
5798  /*
5799  print "Exception catched:\n";
5800  print "Code: ".$e->getCode()."\n";
5801  print "Message: ".$e->getMessage()."\n";
5802  print "Line: ".$e->getLine();
5803  // error in XML
5804  print "\n<br>ERRORXSLT:".$this->id.$this->title."\n";
5805  print "\n=========RAWDATA=================\n";
5806  print $avalue;
5807  print "\n=========XMLDATA=================\n";
5808  print_r2($xmldata);
5809  exit;*/
5810  }
5811  //restore_error_handler();
5812  if ($dom) {
5813  $xmlout = $xslt->transformToXML($dom);
5814  $dxml = new DomDocument();
5815  $dxml->loadXML($xmlout);
5816  //office:text
5817  $ot = $dxml->getElementsByTagNameNS("urn:oasis:names:tc:opendocument:xmlns:office:1.0", "text");
5818  $ot1 = $ot->item(0);
5819  $officetext = $ot1->ownerDocument->saveXML($ot1);
5820  $htmlval = str_replace(array(
5821  '<office:text>',
5822  '</office:text>',
5823  '<office:text/>'
5824  ) , "", $officetext);
5825  // work around : tables are not in paragraph
5826  $htmlval = preg_replace("/(<text:p>[\s]*<table:table )/ ", "<table:table ", $htmlval);
5827  $htmlval = preg_replace("/(<\/table:table>[\s]*<\/text:p>)/ ", "</table:table> ", $htmlval);
5828 
5829  $pppos = mb_strrpos($htmlval, '</text:p>');
5830 
5831  $htmlval = sprintf('<text:section text:style-name="Sect%s" text:name="Section%s" aid="%s">%s</text:section>', $attrid, $attrid, $attrid, $htmlval);
5832  } else {
5833 
5834  addWarningMsg(sprintf(_("incorrect conversion HTML to ODT %s") , $this->title));
5835  }
5836  //$htmlval=preg_replace("/<\/?(\w+[^:]?|\w+\s.*?)>//g", "",$htmlval );
5837  break;
5838 
5839  case 'date':
5840  if (($aformat != "") && (trim($avalue) != "")) {
5841  if ($avalue) $htmlval = strftime($aformat, stringDateToUnixTs($avalue));
5842  else $htmlval = $avalue;
5843  } elseif (trim($avalue) == "") {
5844  $htmlval = "";
5845  } else {
5846  $htmlval = stringDateToLocaleDate($avalue);
5847  }
5848  $aformat = "";
5849  break;
5850 
5851  case 'time':
5852  if ($aformat != "") {
5853  if ($avalue) $htmlval = strftime($aformat, strtotime($avalue));
5854  else $htmlval = $avalue;
5855  $aformat = "";
5856  } else {
5857  $htmlval = substr($avalue, 0, 5); // do not display second
5858 
5859  }
5860 
5861  break;
5862 
5863  case 'timestamp':
5864  if (($aformat != "") && (trim($avalue) != "")) {
5865  if ($avalue) $htmlval = strftime($aformat, stringDateToUnixTs($avalue));
5866  else $htmlval = $avalue;
5867  } elseif (trim($avalue) == "") {
5868  $htmlval = "";
5869  } else {
5870  $htmlval = stringDateToLocaleDate($avalue);
5871  }
5872  $aformat = "";
5873  break;
5874 
5875  case 'ifile':
5876  $lay = new Layout("FDL/Layout/viewifile.xml", $action);
5877  $lay->set("aid", $oattr->id);
5878  $lay->set("id", $this->id);
5879  $lay->set("iheight", $oattr->getOption("height", "200px"));
5880  $htmlval = $lay->gen();
5881 
5882  break;
5883 
5884  case 'color':
5885  $htmlval = sprintf("<span style=\"background-color:%s\">%s</span>", $avalue, $avalue);
5886  break;
5887 
5888  default:
5889  $htmlval = stripslashes($avalue);
5890  $htmlval = str_replace(array(
5891  "<",
5892  ">",
5893  '&'
5894  ) , array(
5895  "&lt;",
5896  "&gt;",
5897  "&amp;"
5898  ) , $htmlval);
5899 
5900  break;
5901  }
5902 
5903  if (($aformat != "") && ($atype != "doc") && ($atype != "array") && ($atype != "option")) {
5904  //printf($htmlval);
5905  $htmlval = sprintf($aformat, $htmlval);
5906  }
5907 
5908  $thtmlval[$kvalue] = $htmlval;
5909  }
5910 
5911  return implode("<text:tab/>", $thtmlval);
5912  }
5913  /**
5914  * Control Access privilege for document for current user
5915  *
5916  * @param string $aclname identificator of the privilege to test
5917  * @return string empty means access granted else it is an error message (access unavailable)
5918  */
5919  public function Control($aclname)
5920  {
5921  // --------------------------------------------------------------------
5922  if (($this->IsAffected())) {
5923 
5924  if (($this->profid <= 0) || ($this->userid == 1)) {
5925  // No control if there is no profile or it's the admin user
5926  return "";
5927  }
5928  $err = $this->controlId($this->profid, $aclname);
5929  if ($err != '') {
5930  if ($this->isConfidential()) {
5931  return sprintf(_("no privilege %s for %s") , $aclname, $this->getTitle());
5932  } else {
5933  return $err;
5934  }
5935  }
5936  // Edit rights on profiles must also be controlled by the 'modifyacl' acl
5937  if (($aclname == 'edit' || $aclname == 'delete' || $aclname == 'unlock') && $this->isRealProfile()) {
5938  $err = $this->controlId($this->profid, 'modifyacl');
5939  if ($err != '') {
5940  return $err;
5941  }
5942  }
5943  }
5944 
5945  return "";
5946  }
5947  /**
5948  * Control Access privilege for document for other user
5949  *
5950  * @param int $uid user identificator
5951  * @param string $aclname identificator of the privilege to test
5952  * @return string empty means access granted else it is an error message (access unavailable)
5953  */
5954  public function ControlUser($uid, $aclname)
5955  {
5956  // --------------------------------------------------------------------
5957  if ($this->IsAffected()) {
5958  if (($this->profid <= 0) || ($uid == 1)) return ""; // no profil or admin
5959  if (!$uid) return _("control :: user identificator is null");
5960  return $this->controlUserId($this->profid, $uid, $aclname);
5961  }
5962  return "";
5963  }
5964  /**
5965  * verify that the document exists and is not in trash (not a zombie)
5966  * @return bool
5967  */
5968  final public function isAlive()
5969  {
5970  return ((DbObj::isAffected()) && ($this->doctype != 'Z'));
5971  }
5972  /**
5973  * add several triggers to update different tables (such as docread) or attributes (such as values)
5974  * @param bool $onlydrop set to false for only drop triggers
5975  */
5976  final public function SqlTrigger($onlydrop = false, $code = false)
5977  {
5978 
5979  if (get_class($this) == "DocFam") {
5980  $cid = "fam";
5981  } else {
5982  if ($this->doctype == 'C') return;
5983  if (intval($this->fromid) == 0) return;
5984 
5985  $cid = $this->fromid;
5986  }
5987 
5988  $sql = "";
5989  // delete all relative triggers
5990  $sql.= "select droptrigger('doc" . $cid . "');";
5991  if ($onlydrop) return $sql; // only drop
5992  if ($code) {
5993  $lay = new Layout("FDL/Layout/sqltrigger.xml");
5994  $na = $this->GetNormalAttributes();
5995  $tvalues = array();
5996  $tsearch = array();
5997  foreach ($na as $k => $v) {
5998  if (($v->type != "array") && ($v->type != "frame") && ($v->type != "tab") && ($v->type != "idoc")) {
5999  $tvalues[] = array(
6000  "attrid" => $k
6001  );
6002  if (($v->type != "file") && ($v->type != "image") && ($v->type != "password")) $tsearch[] = array(
6003  "attrid" => $k
6004  );
6005  }
6006  if ($v->type == "file") {
6007  $files[] = array(
6008  "attrid" => $k . "_txt",
6009  "vecid" => $k . "_vec"
6010  );
6011  $tsearch[] = array(
6012  "attrid" => $k . "_txt"
6013  );
6014  }
6015  }
6016  $na = $this->GetAbstractAttributes();
6017  foreach ($na as $k => $v) {
6018  if (($v->type != "array") && ($v->type != "file") && ($v->type != "image") && ($v->type != "password")) {
6019  $tabstract[] = array(
6020  "attrid" => $k
6021  );
6022  }
6023  }
6024  $lay->setBlockData("ATTRFIELD", $tvalues);
6025  $lay->setBlockData("SEARCHFIELD", $tsearch);
6026  $lay->setBlockData("ABSATTR", $tabstract);
6027  $lay->setBlockData("FILEATTR", $files);
6028  $lay->setBlockData("FILEATTR2", $files);
6029  $lay->setBlockData("FILEATTR3", $files);
6030  $lay->set("hasattr", (count($tvalues) > 0));
6031  $lay->set("hassattr", (count($tsearch) > 0));
6032  $lay->set("hasabsattr", (count($tabstract) > 0));
6033  $lay->set("docid", $this->fromid);
6034  $sql = $lay->gen();
6035  } else {
6036 
6037  if (is_array($this->attributes->fromids)) {
6038  foreach ($this->attributes->fromids as $k => $v) {
6039 
6040  $sql.= "create trigger UV{$cid}_$v BEFORE INSERT OR UPDATE ON doc$cid FOR EACH ROW EXECUTE PROCEDURE upval$v();";
6041  }
6042  }
6043  // the reset trigger must begin with 'A' letter to be proceed first (pgsql 7.3.2)
6044  if ($cid != "fam") {
6045  $sql.= "create trigger AUVR{$cid} BEFORE UPDATE ON doc$cid FOR EACH ROW EXECUTE PROCEDURE resetvalues();";
6046  $sql.= "create trigger VFULL{$cid} BEFORE INSERT OR UPDATE ON doc$cid FOR EACH ROW EXECUTE PROCEDURE fullvectorize$cid();";
6047  }
6048  $sql.= "create trigger zread{$cid} AFTER INSERT OR UPDATE OR DELETE ON doc$cid FOR EACH ROW EXECUTE PROCEDURE setread();";
6049  $sql.= "create trigger FIXDOC{$cid} AFTER INSERT ON doc$cid FOR EACH ROW EXECUTE PROCEDURE fixeddoc();";
6050  }
6051  return $sql;
6052  }
6053  /**
6054  * add specials SQL indexes
6055  */
6056  final public function GetSqlIndex()
6057  {
6058  $t = "";
6059  $id = $this->fromid;
6060  if ($this->sqlindex) $sqlindex = array_merge($this->sqlindex, Doc::$sqlindex);
6061  else $sqlindex = Doc::$sqlindex;
6062  foreach ($sqlindex as $k => $v) {
6063 
6064  if ($v["unique"]) $unique = "unique";
6065  else $unique = "";
6066  if ($v["using"] != "") {
6067 
6068  if ($v["using"][0] == "@") {
6069  $v["using"] = getParam(substr($v["using"], 1));
6070  }
6071  $t.= sprintf("CREATE $unique INDEX %s$id on doc$id using %s(%s);\n", $k, $v["using"], $v["on"]);
6072  } else {
6073  $t.= sprintf("CREATE $unique INDEX %s$id on doc$id(%s);\n", $k, $v["on"]);
6074  }
6075  }
6076  return $t;
6077  }
6078  /**
6079  * return the basename of template file
6080  * @return string (return null if template not found)
6081  */
6082  public function getZoneFile($zone)
6083  {
6084  $index = - 1;
6085  if ($zone == "") {
6086  return null;
6087  }
6088 
6089  $reg = $this->parseZone($zone);
6090  if (is_array($reg)) {
6091  $aid = $reg['layout'];
6092  if ($reg['index'] != '') {
6093  $index = $reg['index'];
6094  }
6095  $oa = $this->getAttribute($aid);
6096  if ($oa) {
6097  if ($oa->usefor != 'Q') {
6098  $template = $this->getValue($oa->id);
6099  } else {
6100  $template = $this->getParamValue($aid);
6101  }
6102  if ($index >= 0) {
6103  $tt = $this->_val2array($template);
6104  $template = $tt[$index];
6105  }
6106 
6107  if ($template == "") {
6108  return null;
6109  }
6110 
6111  return $this->vault_filename_fromvalue($template, true);
6112  }
6113  return getLayoutFile($reg['app'], ($aid));
6114  }
6115  }
6116  /**
6117  * return the character in third part of zone
6118  * @return char
6119  */
6120  public function getZoneOption($zone = "")
6121  {
6122  if ($zone == "") {
6123  $zone = $this->defaultview;
6124  }
6125 
6126  $zoneElements = $this->parseZone($zone);
6127  if ($zoneElements === false) {
6128  return '';
6129  }
6130 
6131  return $zoneElements['modifier'];
6132  }
6133  /**
6134  * return the characters in fourth part of zone
6135  * @return string
6136  */
6137  public function getZoneTransform($zone = "")
6138  {
6139  if ($zone == "") {
6140  $zone = $this->defaultview;
6141  }
6142 
6143  $zoneElements = $this->parseZone($zone);
6144  if ($zoneElements === false) {
6145  return '';
6146  }
6147 
6148  return $zoneElements['transform'];
6149  }
6150  /**
6151  * set default values define in family document
6152  * the format of the string which define default values is like
6153  * [US_ROLE|director][US_SOCIETY|alwaysNet]...
6154  * @param string $defval the default values
6155  * @param bool $method set to false if don't want interpreted values
6156  * @param bool $forcedefault force default values
6157  */
6158  final public function setDefaultValues($tdefval, $method = true, $forcedefault = false)
6159  {
6160  if (is_array($tdefval)) {
6161  foreach ($tdefval as $aid => $dval) {
6162  $oattr = $this->getAttribute($aid);
6163 
6164  $ok = false;
6165  if (empty($oattr)) $ok = false;
6166  elseif (!method_exists($oattr, "inArray")) $ok = false;
6167  elseif ($forcedefault) $ok = true;
6168  elseif (!$oattr->inArray()) $ok = true;
6169  elseif ($oattr->fieldSet->format != "empty" && $oattr->fieldSet->getOption("empty") != "yes") {
6170  $ok = true;
6171  }
6172  if ($ok) {
6173  if ($method) {
6174  $this->setValue($aid, $this->GetValueMethod($dval));
6175  } else {
6176  $this->$aid = $dval; // raw data
6177 
6178  }
6179  } else {
6180  // TODO raise exception
6181 
6182  }
6183  }
6184  }
6185  }
6186  /**
6187  * set default name reference
6188  * if no name a new name will ne computed from its initid and family name
6189  * the new name is set to name attribute
6190  * @return string error messahe (empty means OK).
6191  */
6192  final public function setNameAuto()
6193  {
6194  if (($this->name == "") && ($this->initid > 0)) {
6195  $dfam = $this->getFamDoc();
6196  if ($dfam->name == "") return sprintf("no family name %s", $dfam->id);
6197  $this->name = $dfam->name . '_' . $this->initid;
6198  $err = $this->modify(true, array(
6199  "name"
6200  ) , true);
6201  }
6202  return $err;
6203  }
6204  /**
6205  * set all attribute in W visibility
6206  *
6207  *
6208  */
6210  {
6211  // transform hidden to writted attribut for default document
6212  $listattr = $this->GetAttributes();
6213  foreach ($listattr as $i => $attr) {
6214  if (($attr->mvisibility == "H") || ($attr->mvisibility == "I") || ($attr->mvisibility == "R") || ($attr->mvisibility == "S")) {
6215  $this->attributes->attr[$i]->mvisibility = "W";
6216  }
6217  }
6218  }
6219  /**
6220  * Return the main path relation
6221  * list of prelid properties (primary relation)
6222  * the first item is the direct parent, the second:the grand-parent , etc.
6223  * @return array key=id , value=title of relation
6224  */
6225  function getMainPath()
6226  {
6227  $tr = array();
6228 
6229  if ($this->prelid > 0) {
6230 
6231  $d = getTDoc($this->dbaccess, $this->prelid);
6232  $fini = false;
6233  while (!$fini) {
6234  if ($d) {
6235  if (controlTDoc($d, "view")) {
6236  if (!in_array($d["initid"], array_keys($tr))) {
6237  $tr[$d["initid"]] = $d["title"];
6238  if ($d["prelid"] > 0) $d = getTDoc($this->dbaccess, $d["prelid"]);
6239  else $fini = true;
6240  } else $fini = true;
6241  } else $fini = true;
6242  } else {
6243  $fini = true;
6244  }
6245  }
6246  }
6247  return $tr;
6248  }
6249  /**
6250  * generate HTML code for view doc
6251  * @param string $layout layout to use to view document
6252  * @param string $target window target name for hyperlink destination
6253  * @param bool $ulink if false hyperlink are not generated
6254  * @param bool $abstract if true only abstract attribute are generated
6255  * @param bool $changelayout if true the internal layout ($this->lay) will be replace by the new layout
6256  */
6257  final public function viewDoc($layout = "FDL:VIEWBODYCARD", $target = "_self", $ulink = true, $abstract = false, $changelayout = false)
6258  {
6259  global $action;
6260 
6261  $reg = $this->parseZone($layout);
6262  if ($reg === false) {
6263  return sprintf(_("error in pzone format %s") , $layout);
6264  }
6265 
6266  if (array_key_exists('args', $reg)) {
6267  // in case of arguments in zone
6268  global $ZONE_ARGS;
6269  $layout = $reg['fulllayout'];
6270  if (array_key_exists('argv', $reg)) {
6271  foreach ($reg['argv'] as $k => $v) {
6272  $ZONE_ARGS[$k] = $v;
6273  }
6274  }
6275  }
6276 
6277  if (!$changelayout) {
6278  $play = $this->lay;
6279  }
6280  $binary = ($this->getZoneOption($layout) == "B");
6281 
6282  $tplfile = $this->getZoneFile($layout);
6283 
6284  $ext = getFileExtension($tplfile);
6285  if (strtolower($ext) == "odt") {
6286  include_once ('Class.OOoLayout.php');
6287  $target = "ooo";
6288  $ulink = false;
6289  $this->lay = new OOoLayout($tplfile, $action, $this);
6290  } else {
6291  $this->lay = new Layout($tplfile, $action, "");
6292  }
6293  //if (! file_exists($this->lay->file)) return sprintf(_("template file (layout [%s]) not found"), $layout);
6294  $this->lay->setZone($reg);
6295 
6296  $this->lay->set("_readonly", ($this->Control('edit') != ""));
6297  $method = strtok(strtolower($reg['layout']) , '.');
6298 
6299  if (method_exists($this, $method)) {
6300  try {
6301  $this->$method($target, $ulink, $abstract);
6302  }
6303  catch(Exception $e) {
6304  if ((!file_exists($this->lay->file) && (!$this->lay->template))) {
6305  return sprintf(_("template file (layout [%s]) not found") , $layout);
6306  } else throw $e;
6307  }
6308  } else {
6309  $this->viewdefaultcard($target, $ulink, $abstract);
6310  }
6311 
6312  if ((!file_exists($this->lay->file) && (!$this->lay->template))) {
6313  return sprintf(_("template file (layout [%s]) not found") , $layout);
6314  }
6315 
6316  $laygen = $this->lay->gen();
6317 
6318  if (!$changelayout) $this->lay = $play;
6319 
6320  if (!$ulink) {
6321  // suppress href attributes
6322  return preg_replace(array(
6323  "/href=\"index\.php[^\"]*\"/i",
6324  "/onclick=\"[^\"]*\"/i",
6325  "/ondblclick=\"[^\"]*\"/i"
6326  ) , array(
6327  "",
6328  "",
6329  ""
6330  ) , $laygen);
6331  }
6332  if ($target == "mail") {
6333  // suppress session id
6334  return preg_replace("/\?session=[^&]*&/", "?", $laygen);
6335  }
6336  if ($binary && ($target != "ooo")) {
6337  // set result into file
6338  $tmpfile = uniqid(getTmpDir() . "/fdllay") . ".html";
6339  $nc = file_put_contents($tmpfile, $laygen);
6340  $laygen = $tmpfile;
6341  }
6342 
6343  return $laygen;
6344  }
6345  // --------------------------------------------------------------------
6346 
6347  /**
6348  * default construct layout for view card containt
6349  *
6350  * @param string $target window target name for hyperlink destination
6351  * @param bool $ulink if false hyperlink are not generated
6352  * @param bool $abstract if true only abstract attribute are generated
6353  * @param bool $viewhidden if true view also hidden attributes
6354  */
6355  final public function viewdefaultcard($target = "_self", $ulink = true, $abstract = false, $viewhidden = false)
6356  {
6357  $this->viewattr($target, $ulink, $abstract, $viewhidden);
6358  $this->viewprop($target, $ulink, $abstract);
6359  }
6360  // --------------------------------------------------------------------
6361 
6362  /**
6363  * construct layout for view card containt
6364  *
6365  * @param string $target window target name for hyperlink destination
6366  * @param bool $ulink if false hyperlink are not generated
6367  * @param bool $abstract if true only abstract attribute are generated
6368  * @param bool $onlyopt if true only optionnal attributes are displayed
6369  */
6370  function viewbodycard($target = "_self", $ulink = true, $abstract = false, $onlyopt = false)
6371  {
6372  global $action;
6373 
6374  $frames = array();
6375  if ($abstract) {
6376  // only 3 properties for abstract mode
6377  $listattr = $this->GetAbstractAttributes();
6378  } else {
6379  $listattr = $this->GetNormalAttributes($onlyopt);
6380  }
6381 
6382  $nattr = count($listattr); // attributes list count
6383  $k = 0; // number of frametext
6384  $v = 0; // number of value in one frametext
6385  $nbimg = 0; // number of image in one frametext
6386  $currentFrameId = "";
6387 
6388  $changeframe = false; // is true when need change frame
6389  $tableframe = array();
6390  $tableimage = array();
6391  $ttabs = array();
6392 
6393  $iattr = 0;
6394  $firsttab = false;
6395  $onlytab = strtolower(getHttpVars("onlytab"));
6396  $tabonfly = false; // I want tab on fly
6397  $showonlytab = ($onlytab ? $onlytab : false);
6398  if ($onlytab) {
6399  $this->addUTag($this->userid, "lasttab", $onlytab);
6400  }
6401  foreach ($listattr as $i => $attr) {
6402  if ($onlytab && ($attr->fieldSet->id != $onlytab && $attr->fieldSet->fieldSet->id != $onlytab)) continue;
6403 
6404  $iattr++;
6405  //------------------------------
6406  // Compute value element
6407  $value = chop($this->GetValue($i));
6408  if (!$attr->fieldSet) {
6409  addWarningMsg(sprintf(_("unknow set for attribute %s %s") , $attr->id, $attr->getLabel()));
6410  continue;
6411  }
6412  $frametpl = $attr->fieldSet->getOption("viewtemplate");
6413  if ($attr->fieldSet && ($frametpl && $attr->fieldSet->type != "array")) {
6414  $goodvalue = false;
6415  if ($currentFrameId != $attr->fieldSet->id) {
6416  if (($attr->fieldSet->mvisibility != "H") && ($attr->fieldSet->mvisibility != "I")) {
6417  $changeframe = true;
6418  $currentFrameId = $attr->fieldSet->id;
6419  $currentFrame = $attr->fieldSet;
6420  $v++;
6421  }
6422  }
6423  } else {
6424  $goodvalue = ((($value != "") || ($attr->type == "array") || $attr->getOption("showempty")) && ($attr->mvisibility != "H") && ($attr->mvisibility != "I") && ($attr->mvisibility != "O") && (!$attr->inArray()));
6425  if (($attr->type == "array") && (!$attr->getOption("showempty"))) {
6426  if (count($this->getAValues($attr->id)) == 0) $goodvalue = false;
6427  }
6428 
6429  if ($goodvalue) {
6430  // detect first tab
6431  $toptab = $attr->getTab();
6432  if ($toptab) $tabonfly = ($toptab->getOption("viewonfly") == "yes");
6433  if ($tabonfly && (!$showonlytab)) {
6434  $ut = $this->getUtag("lasttab");
6435  if ($ut) $showonlytab = $ut->comment;
6436  elseif ($attr->fieldSet->id && $attr->fieldSet->fieldSet) {
6437  $showonlytab = $attr->fieldSet->fieldSet->id;
6438  }
6439  }
6440  $attrInNextTab = ($tabonfly && $toptab && ($toptab->id != $showonlytab));
6441  if (!$attrInNextTab) {
6442  $viewtpl = $attr->getOption("viewtemplate");
6443  if ($viewtpl) {
6444  if ($viewtpl == "none") {
6445  $htmlvalue = '';
6446  } else {
6447  if ($this->getZoneOption($viewtpl) == 'S') {
6448  $attr->setOption("vlabel", "none");
6449  }
6450  $htmlvalue = sprintf("[ZONE FDL:VIEWTPL?id=%d&famid=%d&target=%s&zone=%s]", $this->id, $this->fromid, $target, $viewtpl);
6451  }
6452  } else {
6453  if ((($value == "") && ($attr->type != "array")) || (($attr->type == "array") && (count($this->getAValues($attr->id)) == 0))) $htmlvalue = $attr->getOption("showempty");
6454  else $htmlvalue = $this->GetHtmlValue($attr, $value, $target, $ulink);
6455  }
6456  } else {
6457  $htmlvalue = false; // display defer
6458 
6459  }
6460  } else $htmlvalue = "";
6461 
6462  if (($htmlvalue === false) || ($goodvalue)) { // to define when change frame
6463  if ($currentFrameId != $attr->fieldSet->id) {
6464  if (($currentFrameId != "") && ($attr->fieldSet->mvisibility != "H")) $changeframe = true;
6465  }
6466  }
6467  }
6468  //------------------------------
6469  // change frame if needed
6470  if ($changeframe) { // to generate fieldset
6471  $changeframe = false;
6472  if (($v + $nbimg) > 0) { // one value detected
6473  $oaf = $this->getAttribute($currentFrameId);
6474  $frames[$k]["frametext"] = ($oaf && $oaf->getOption("vlabel") != "none") ? mb_ucfirst($this->GetLabel($currentFrameId)) : "";
6475  $frames[$k]["frameid"] = $currentFrameId;
6476  $frames[$k]["bgcolor"] = $oaf ? $oaf->getOption("bgcolor", false) : false;
6477 
6478  $frames[$k]["tag"] = "";
6479  $frames[$k]["TAB"] = false;
6480  if (($currentFrame->fieldSet->id != "") && ($currentFrame->fieldSet->id != "FIELD_HIDDENS")) {
6481  $frames[$k]["tag"] = "TAG" . $currentFrame->fieldSet->id;
6482  $frames[$k]["TAB"] = true;
6483  $ttabs[$currentFrame->fieldSet->id] = array(
6484  "tabid" => $currentFrame->fieldSet->id,
6485  "tabtitle" => ($currentFrame->fieldSet->getOption("vlabel") == "none") ? '&nbsp;' : mb_ucfirst($currentFrame->fieldSet->getLabel())
6486  );
6487  }
6488  $frames[$k]["viewtpl"] = ($frametpl != "");
6489  $frames[$k]["zonetpl"] = ($frametpl != "") ? sprintf("[ZONE FDL:VIEWTPL?id=%d&famid=%d&target=%s&zone=%s]", $this->id, $this->fromid, $target, $frametpl) : '';
6490 
6491  $frames[$k]["rowspan"] = $v + 1; // for images cell
6492  $frames[$k]["TABLEVALUE"] = "TABLEVALUE_$k";
6493 
6494  $this->lay->SetBlockData($frames[$k]["TABLEVALUE"], $tableframe);
6495  $frames[$k]["IMAGES"] = "IMAGES_$k";
6496  $this->lay->SetBlockData($frames[$k]["IMAGES"], $tableimage);
6497  $frames[$k]["notloaded"] = false;
6498  if ($oaf->type == "frame" && (count($tableframe) + count($tableimage)) == 0) {
6499  if (!$frames[$k]["viewtpl"]) {
6500  $frames[$k]["viewtpl"] = true;
6501  $frames[$k]["zonetpl"] = _("Loading...");
6502  $frames[$k]["notloaded"] = true;
6503  }
6504  }
6505  unset($tableframe);
6506  unset($tableimage);
6507  $tableframe = array();
6508  $tableimage = array();
6509  $k++;
6510  }
6511  $v = 0;
6512  $nbimg = 0;
6513  }
6514  if ($htmlvalue === false) {
6515  $goodvalue = false;
6516  if ($currentFrameId != $attr->fieldSet->id) {
6517  if (($attr->fieldSet->mvisibility != "H") && ($attr->fieldSet->mvisibility != "I")) {
6518  $changeframe = true;
6519  $currentFrameId = $attr->fieldSet->id;
6520  $currentFrame = $attr->fieldSet;
6521  $v++;
6522  }
6523  }
6524  }
6525  //------------------------------
6526  // Set the table value elements
6527  if ($goodvalue) {
6528  switch ($attr->type) {
6529  case "image":
6530  $tableimage[$nbimg]["imgsrc"] = $htmlvalue;
6531  $tableimage[$nbimg]["itarget"] = ($action->Read("navigator", "") == "NETSCAPE") ? "_self" : "_blank";
6532  $width = $attr->getOption("iwidth", "80px");
6533  $tableimage[$nbimg]["imgwidth"] = $width;
6534  if (strstr($htmlvalue, 'EXPORTFILE')) $tableimage[$nbimg]["imgthumbsrc"] = $htmlvalue . "&width=" . intval($width);
6535  else $tableimage[$nbimg]["imgthumbsrc"] = $htmlvalue;
6536  break;
6537 
6538  default:
6539  $tableframe[$v]["nonelabel"] = false;
6540  $tableframe[$v]["normallabel"] = true;
6541  $tableframe[$v]["uplabel"] = false;
6542  $tableframe[$v]["value"] = $htmlvalue;
6543  break;
6544  }
6545 
6546  if (($attr->fieldSet->mvisibility != "H") && ($htmlvalue !== "" || $goodvalue)) {
6547  $currentFrameId = $attr->fieldSet->id;
6548  $currentFrame = $attr->fieldSet;
6549  }
6550  // print name except image (printed otherthere)
6551  if ($attr->type != "image") {
6552  $tableframe[$v]["wvalue"] = (($attr->type == "array") && ($attr->getOption("vlabel") == "up" || $attr->getOption("vlabel") == "none")) ? "1%" : "30%"; // width
6553  $tableframe[$v]["ndisplay"] = "inline";
6554 
6555  if ($attr->getOption("vlabel") == "none") {
6556  $tableframe[$v]["nonelabel"] = true;
6557  $tableframe[$v]["normallabel"] = false;
6558  } else if ($attr->getOption("vlabel") == "up") {
6559  if ($attr->type == "array") { // view like none label
6560  $tableframe[$v]["nonelabel"] = true;
6561  $tableframe[$v]["normallabel"] = false;
6562  } else {
6563  $tableframe[$v]["normallabel"] = false;
6564  $tableframe[$v]["uplabel"] = true;
6565  }
6566  }
6567  $tableframe[$v]["name"] = $this->GetLabel($attr->id);
6568  if (($attr->type == "htmltext") && (count($tableframe) == 1)) {
6569  $keys = array_keys($listattr);
6570  $na = $listattr[$keys[$iattr]]; // next attribute
6571  if ($na->fieldSet->id != $attr->fieldSet->id) { // only when only one attribute in frame
6572  $tableframe[$v]["ndisplay"] = "none";
6573  $tableframe[$v]["wvalue"] = "1%";
6574  }
6575  }
6576 
6577  $tableframe[$v]["classback"] = ($attr->usefor == "O") ? "FREEDOMOpt" : "FREEDOMBack1";
6578  $v++;
6579  } else {
6580  $tableimage[$nbimg]["imgalt"] = $this->GetLabel($attr->id);
6581  $nbimg++;
6582  }
6583  }
6584  }
6585 
6586  if (($v + $nbimg) > 0) // // last fieldset
6587  {
6588  $oaf = $this->getAttribute($currentFrameId);
6589  if ($oaf) $frames[$k]["frametext"] = ($oaf->getOption("vlabel") != "none") ? mb_ucfirst($this->GetLabel($currentFrameId)) : "";
6590  else $frames[$k]["frametext"] = '';
6591  $frames[$k]["frameid"] = $currentFrameId;
6592  $frames[$k]["tag"] = "";
6593  $frames[$k]["TAB"] = false;
6594  $frames[$k]["viewtpl"] = ($frametpl != "");
6595  $frames[$k]["zonetpl"] = ($frametpl != "") ? sprintf("[ZONE FDL:VIEWTPL?id=%d&famid=%d&target=%s&zone=%s]", $this->id, $this->fromid, $target, $frametpl) : '';
6596 
6597  $frames[$k]["bgcolor"] = $oaf ? $oaf->getOption("bgcolor", false) : false;
6598  if (($currentFrame->fieldSet->id != "") && ($currentFrame->fieldSet->id != "FIELD_HIDDENS")) {
6599  $frames[$k]["tag"] = "TAG" . $currentFrame->fieldSet->id;
6600  $frames[$k]["TAB"] = true;
6601  $ttabs[$currentFrame->fieldSet->id] = array(
6602  "tabid" => $currentFrame->fieldSet->id,
6603  "tabtitle" => ($currentFrame->fieldSet->getOption("vlabel") == "none") ? '&nbsp;' : mb_ucfirst($currentFrame->fieldSet->getLabel())
6604  );
6605  }
6606  $frames[$k]["rowspan"] = $v + 1; // for images cell
6607  $frames[$k]["TABLEVALUE"] = "TABLEVALUE_$k";
6608 
6609  $this->lay->SetBlockData($frames[$k]["TABLEVALUE"], $tableframe);
6610 
6611  $frames[$k]["IMAGES"] = "IMAGES_$k";
6612  $this->lay->SetBlockData($frames[$k]["IMAGES"], $tableimage);
6613  $frames[$k]["notloaded"] = false;
6614  if ($oaf->type == "frame" && (count($tableframe) + count($tableimage)) == 0) {
6615  if (!$frames[$k]["viewtpl"]) {
6616  $frames[$k]["viewtpl"] = true;
6617  $frames[$k]["zonetpl"] = _("Loading...");
6618  $frames[$k]["notloaded"] = true;
6619  }
6620  }
6621  }
6622  // Out
6623  $this->lay->SetBlockData("TABLEBODY", $frames);
6624  $this->lay->SetBlockData("TABS", $ttabs);
6625  $this->lay->Set("ONETAB", count($ttabs) > 0);
6626  $this->lay->Set("NOTAB", ($target == "mail") || $onlytab);
6627  $this->lay->Set("docid", $this->id);
6628 
6629  if (count($ttabs) > 0) {
6630  $this->lay->Set("firsttab", false);
6631  $ut = $this->getUtag("lasttab");
6632  if ($ut) $firstopen = $ut->comment; // last memo tab
6633  else $firstopen = false;
6634  foreach ($ttabs as $k => $v) {
6635  $oa = $this->getAttribute($k);
6636  if ($oa->getOption("firstopen") == "yes") $this->lay->set("firsttab", $k);
6637  if ($firstopen == $oa->id) $this->lay->Set("firsttab", $k);
6638  }
6639  }
6640  }
6641  /**
6642  * write layout for thumb view
6643  */
6644  function viewthumbcard($target = "finfo", $ulink = true, $abstract = true)
6645  {
6646  $this->viewabstractcard($target, $ulink, $abstract);
6647  $this->viewprop($target, $ulink, $abstract);
6648  $this->lay->set("iconsrc", $this->getIcon());
6649  $state = $this->getState();
6650  if ($state != "") $this->lay->set("state", _($state));
6651  else $this->lay->set("state", "");
6652  }
6653  /**
6654  * layout for view answers
6655  */
6656  function viewanswers($target = "finfo", $ulink = true, $abstract = true)
6657  {
6658  if (!$this->isAlive()) $err = (sprintf(_("unknow document reference '%s'") , GetHttpVars("docid")));
6659  if ($err == "") $err = $this->control("wask");
6660  if ($err) {
6661  $this->lay->template = $err;
6662  return;
6663  }
6664 
6665  $answers = $this->getWasks(false);
6666 
6667  foreach ($answers as $ka => $ans) {
6668  $utags = $this->searchUTags("ASK_" . $ans["waskid"], false, true);
6669  $wask = new_doc($this->dbaccess, $ans["waskid"]);
6670  $wask->set($this);
6671 
6672  $taguid = array();
6673 
6674  $t = array();
6675  foreach ($utags as $k => $v) {
6676  $taguid[] = $v["uid"];
6677  $t[$k] = $v;
6678  $t[$k]["label"] = $wask->getAskLabel($v["comment"]);
6679  $t[$k]["ask"] = $wask->getvalue("was_ask");
6680  }
6681 
6682  uasort($t, array(
6683  get_class($this) ,
6684  "_cmpanswers"
6685  ));
6686  $prevc = '';
6687  $odd = 0;
6688  foreach ($t as $k => $v) {
6689  if ($v["comment"] != $prevc) {
6690  $prevc = $v["comment"];
6691  $odd++;
6692  }
6693  $t[$k]["class"] = (($odd % 2) == 0) ? "evenanswer" : "oddanswer";
6694  }
6695  // find user not answered
6696  $ru = $wask->getUsersForAcl('answer'); // all users must answered
6697  $una = array_diff(array_keys($ru) , $taguid);
6698 
6699  $tna = array();
6700 
6701  $tuna = array();
6702  foreach ($una as $k => $v) {
6703  $tuna[$v] = $ru[$v]["login"];
6704  }
6705 
6706  asort($tuna, SORT_STRING);
6707  foreach ($tuna as $k => $v) {
6708  $tna[] = array(
6709  "login" => $ru[$k]["login"],
6710  "fn" => $ru[$k]["firstname"],
6711  "ln" => $ru[$k]["lastname"]
6712  );
6713  }
6714 
6715  $this->lay->setBlockData("ANSWERS" . $wask->id, $t);
6716  $this->lay->setBlockData("NOTANS" . $wask->id, $tna);
6717  if ($title != "") $title.= ', ';
6718  $title.= $wask->getTitle();
6719 
6720  $this->lay->set("asktitle", $title);
6721  $tw[] = array(
6722  "waskid" => $wask->id,
6723  "nacount" => sprintf(_("number of waiting answers %d") , count($una)) ,
6724  "count" => (count($t) > 1) ? sprintf(_("%d answers") , count($t)) : sprintf(_("%d answer") , count($t)) ,
6725  "ask" => $wask->getValue("was_ask")
6726  );
6727  }
6728  $this->lay->setBlockData("WASK", $tw);
6729  $this->lay->set("docid", $this->id);
6730  }
6731  /**
6732  * to sort answer by response
6733  */
6734  static function _cmpanswers($a, $b)
6735  {
6736  return strcasecmp($a["comment"] . $a["uname"], $b["comment"] . $b["uname"]);
6737  }
6738  /**
6739  * write layout for properties view
6740  */
6741  function viewproperties($target = "finfo", $ulink = true, $abstract = true)
6742  {
6743  global $action;
6744  $this->viewprop($target, $ulink, $abstract);
6745  $this->lay->set("iconsrc", $this->getIcon());
6746  $fdoc = $this->getFamDoc();
6747  $this->lay->Set("ficonsrc", $fdoc->getIcon());
6748  $owner = new User("", abs($this->owner));
6749  $this->lay->Set("username", $owner->firstname . " " . $owner->lastname);
6750  $this->lay->Set("userid", $owner->fid);
6751  $this->lay->Set("lockedby", $this->lay->get("locked"));
6752 
6753  $this->lay->Set("lockdomain", '');
6754  if ($this->locked == - 1) {
6755  $this->lay->Set("lockedid", false);
6756  } else {
6757  $user = new User("", abs($this->locked));
6758  // $this->lay->Set("locked", $user->firstname." ".$user->lastname);
6759  if ($this->lockdomainid) {
6760  $this->lay->Set("lockdomain", sprintf(_("in domain %s") , $this->getDocAnchor($this->lockdomainid, '_blank', true, '', false, true, true)));
6761  }
6762  $this->lay->Set("lockedid", $user->fid);
6763  }
6764  $state = $this->getState();
6765  if ($state != "") {
6766  if (($this->locked == - 1) || ($this->lmodify != 'Y')) $this->lay->Set("state", _($state));
6767  else $this->lay->Set("state", sprintf(_("current (<i>%s</i>)") , _($state)));
6768  } else $this->lay->set("state", _("no state"));
6769  if (is_numeric($this->state) && ($this->state > 0) && (!$this->wid)) {
6770  $this->lay->set("freestate", $this->state);
6771  } else $this->lay->set("freestate", false);
6772  $this->lay->set("setname", ($this->name == "") && $action->parent->Haspermission("FREEDOM_MASTER", "FREEDOM"));
6773  $this->lay->set("hasrevision", ($this->revision > 0));
6774  $this->lay->Set("moddate", strftime("%d/%m/%Y %H:%M:%S", $this->revdate));
6775  $this->lay->set("moddatelabel", _("last modification date"));
6776  if ($this->locked == - 1) {
6777  if ($this->doctype == 'Z') $this->lay->set("moddatelabel", _("suppression date"));
6778  else $this->lay->set("moddatelabel", _("revision date"));
6779  }
6780  if (GetParam("CORE_LANG") == "fr_FR") { // date format depend of locale
6781  $this->lay->Set("revdate", strftime("%a %d %b %Y %H:%M", $this->revdate));
6782  } else {
6783  $this->lay->Set("revdate", strftime("%x %T", $this->revdate));
6784  }
6785  $this->lay->Set("version", $this->version);
6786 
6787  if ((abs($this->profid) > 0) && ($this->profid != $this->id)) {
6788 
6789  $this->lay->Set("profile", $this->getDocAnchor(abs($this->profid) , '_blank', true, '', false, 'latest', true));
6790  } else {
6791  if ($this->profid == 0) {
6792  $this->lay->Set("profile", _("no access control"));
6793  } else {
6794  if ($this->dprofid == 0) {
6795 
6796  $this->lay->Set("profile", $this->getDocAnchor(abs($this->profid) , '_blank', true, _("specific control") , false, 'latest', true));
6797  } else {
6798  $this->lay->Set("profile", $this->getDocAnchor(abs($this->dprofid) , '_blank', true, _("dynamic control") , false, 'latest', true));
6799  }
6800  }
6801  }
6802  if ($this->cvid == 0) {
6803  $this->lay->Set("cview", _("no view control"));
6804  } else {
6805  $this->lay->Set("cview", $this->getDocAnchor($this->cvid, '_blank', true, '', false, 'latest', true));
6806  }
6807  if ($this->prelid == 0) {
6808  $this->lay->Set("prel", _("no folder"));
6809  } else {
6810 
6811  $this->lay->Set("prel", $this->getDocAnchor($this->prelid, '_blank', true, '', false, 'latest', true));
6812  $fldids = $this->getParentFolderIds();
6813 
6814  foreach ($fldids as $fldid) {
6815  if ($fldid != $this->prelid) {
6816  $tfld[] = array(
6817  "fld" => $this->getDocAnchor($fldid, '_blank', true, '', false, 'latest', true)
6818  );
6819  }
6820  }
6821  $this->lay->setBlockData("FOLDERS", $tfld);
6822  }
6823  if ($this->allocated == 0) {
6824  $this->lay->Set("allocate", _("no allocate"));
6825  $this->lay->Set("allocateid", false);
6826  } else {
6827  $user = new User("", ($this->allocated));
6828  $this->lay->Set("allocate", $user->firstname . " " . $user->lastname);
6829  $this->lay->Set("allocateid", $user->fid);
6830  }
6831 
6832  if ($this->forumid == "") {
6833  $this->lay->Set("forum", _("forum disallowed"));
6834  $this->lay->Set("hforum", false);
6835  } else if ($this->forumid === 0) {
6836  $this->lay->Set("forum", _("forum allowed"));
6837  $this->lay->Set("hforum", false);
6838  } else {
6839  if ($this->forumid > 0) $this->lay->Set("forum", _("forum opened"));
6840  else $this->lay->Set("forum", _("forum closed"));
6841  $this->lay->Set("hforum", true);
6842  $this->lay->Set("forumid", abs($this->forumid));
6843  }
6844 
6845  $tms = $this->getAttachedTimers();
6846 
6847  $this->lay->Set("Timers", (count($tms) > 0));
6848  }
6849  /**
6850  * write layout for abstract view
6851  */
6852  function viewabstractcard($target = "finfo", $ulink = true, $abstract = true)
6853  {
6854  $listattr = $this->GetAbstractAttributes();
6855 
6856  $tableframe = array();
6857 
6858  foreach ($listattr as $i => $attr) {
6859  //------------------------------
6860  // Compute value elements
6861  $value = chop($this->GetValue($i));
6862 
6863  if (($value != "") && ($attr->mvisibility != "H") && ($attr->mvisibility != "I")) {
6864 
6865  switch ($attr->type) {
6866  case "image":
6867 
6868  $img = "<IMG align=\"absbottom\" height=\"30px\" SRC=\"" . $this->GetHtmlValue($listattr[$i], $value, $target, $ulink) . "&height=30\">";
6869  $tableframe[] = array(
6870  "name" => $attr->getLabel() ,
6871  "aid" => $attr->id,
6872  "value" => $img
6873  );
6874  break;
6875 
6876  default:
6877  // print values
6878  $tableframe[] = array(
6879  "name" => $attr->getLabel() ,
6880  "aid" => $attr->id,
6881  "value" => $this->GetHtmlValue($listattr[$i], $value, $target, $ulink = 1, -1, true, true)
6882  );
6883 
6884  break;
6885  }
6886  }
6887  }
6888 
6889  $this->lay->SetBlockData("TABLEVALUE", $tableframe);
6890  }
6891  // -----------------------------------
6892  final public function viewattr($target = "_self", $ulink = true, $abstract = false, $viewhidden = false)
6893  {
6894  $listattr = $this->GetNormalAttributes();
6895  // each value can be instanced with L_<ATTRID> for label text and V_<ATTRID> for value
6896  foreach ($listattr as $k => $v) {
6897  $value = chop($this->GetValue($v->id));
6898  //------------------------------
6899  // Set the table value elements
6900  $this->lay->Set("S_" . strtoupper($v->id) , ($value != ""));
6901  // don't see non abstract if not
6902  if ((($v->mvisibility == "H") && (!$viewhidden)) || ($v->mvisibility == "I") || (($abstract) && (!$v->isInAbstract))) {
6903  $this->lay->Set("V_" . strtoupper($v->id) , "");
6904  $this->lay->Set("L_" . strtoupper($v->id) , "");
6905  } else {
6906  if ($target == "ooo") {
6907  if ($v->type == "array") {
6908  $tva = $this->getAValues($v->id);
6909 
6910  $tmkeys = array();
6911  foreach ($tva as $kindex => $kvalues) {
6912  foreach ($kvalues as $kaid => $va) {
6913  $oa = $this->getAttribute($kaid);
6914  if ($oa->getOption("multiple") == "yes") {
6915  // second level
6916  $oa->setOption("multiple", "no"); // needto have values like first level
6917  $values = explode("<BR>", $va);
6918  $ovalues = array();
6919  foreach ($values as $ka => $va) {
6920  $ovalues[] = $this->GetOOoValue($oa, $va);
6921  }
6922  //print_r(array($oa->id=>$ovalues));
6923  $tmkeys[$kindex]["V_" . strtoupper($kaid) ] = $ovalues;
6924  $oa->setOption("multiple", "yes"); // needto have values like first level
6925 
6926  } else {
6927  $tmkeys[$kindex]["V_" . strtoupper($kaid) ] = $this->GetOOoValue($oa, $va);
6928  }
6929  }
6930  }
6931  //print_r($tmkeys);
6932  $this->lay->setRepeatable($tmkeys);
6933  } else {
6934  $ovalue = $this->GetOOoValue($v, $value);
6935  if ($v->isMultiple()) $ovalue = str_replace("<text:tab/>", ', ', $ovalue);
6936  $this->lay->Set("V_" . strtoupper($v->id) , $ovalue);
6937  // print_r(array("V_".strtoupper($v->id)=>$this->GetOOoValue($v, $value),"raw"=>$value));
6938  if ((!$v->inArray()) && ($v->getOption("multiple") == "yes")) {
6939  $values = $this->getTValue($v->id);
6940  $ovalues = array();
6941  $v->setOption("multiple", "no");
6942  foreach ($values as $ka => $va) {
6943  $ovalues[] = $this->GetOOoValue($v, $va);
6944  }
6945  $v->setOption("multiple", "yes");
6946  //print_r(array("V_".strtoupper($v->id)=>$ovalues,"raw"=>$values));
6947  $this->lay->setColumn("V_" . strtoupper($v->id) , $ovalues);
6948  } else {
6949  //$this->lay->Set("V_" . strtoupper($v->id), $this->GetOOoValue($v, $value));
6950 
6951  }
6952  }
6953  } else $this->lay->Set("V_" . strtoupper($v->id) , $this->GetHtmlValue($v, $value, $target, $ulink));
6954  $this->lay->Set("L_" . strtoupper($v->id) , $v->getLabel());
6955  }
6956  }
6957  $listattr = $this->GetFieldAttributes();
6958  // each value can be instanced with L_<ATTRID> for label text and V_<ATTRID> for value
6959  foreach ($listattr as $k => $v) {
6960  $this->lay->Set("L_" . strtoupper($v->id) , $v->getLabel());
6961  }
6962  }
6963  // view doc properties
6964  final public function viewprop($target = "_self", $ulink = true, $abstract = false)
6965  {
6966  foreach ($this->fields as $k => $v) {
6967  if ($target == 'ooo') $this->lay->Set(strtoupper($v) , ($this->$v === null) ? false : str_replace(array(
6968  "<",
6969  ">",
6970  '&'
6971  ) , array(
6972  "&lt;",
6973  "&gt;",
6974  "&amp;"
6975  ) , $this->$v));
6976  else $this->lay->Set(strtoupper($v) , ($this->$v === null) ? false : $this->$v);
6977  }
6978  if ($target == 'ooo') $this->lay->Set("V_TITLE", $this->lay->get("TITLE"));
6979  else $this->lay->Set("V_TITLE", $this->getDocAnchor($this->id, $target, $ulink, false, false));
6980  }
6981  /**
6982  * affect a logical name that can be use as unique reference of a document independant of database
6983  * @param string
6984  * @return string error message if cannot be
6985  */
6987  {
6988  if ($name) {
6989  if (!preg_match("/^[A-Z]/i", $name)) {
6990  return (sprintf(_("name must containt only alphanumeric characters: invalid [%s]") , $name));
6991  } elseif (!$this->isAffected()) {
6992  return (sprintf(_("Cannot set logical name %s because object is not affected") , $name));
6993  } elseif ($this->isAffected() && ($this->name != "") && ($this->doctype != 'Z')) {
6994  return (sprintf(_("Logical name %s already set for %s") , $name, $this->title));
6995  } else {
6996  // verify not use yet
6997  $d = getTDoc($this->dbaccess, $name);
6998  if ($d && $d["doctype"] != 'Z') {
6999  return sprintf(_("Logical name %s already use in document %s") , $name, $d["title"]);
7000  } else {
7001  $this->name = $name;
7002  $err = $this->modify(true, array(
7003  "name"
7004  ) , true);
7005  if ($err != "") {
7006  return $err;
7007  }
7008  }
7009  }
7010  }
7011  }
7012  /**
7013  * view only option values
7014  * @param int $dirid directory to place doc if new doc
7015  * @param bool $onlyopt if true only optionnal attributes are displayed
7016  */
7017  final public function viewoptcard($target = "_self", $ulink = true, $abstract = false)
7018  {
7019  return $this->viewbodycard($target, $ulink, $abstract, true);
7020  }
7021  /**
7022  * edit only option
7023  * @param int $dirid directory to place doc if new doc
7024  * @param bool $onlyopt if true only optionnal attributes are displayed
7025  */
7026  final public function editoptcard($target = "_self", $ulink = true, $abstract = false)
7027  {
7028  return $this->editbodycard($target, $ulink, $abstract, true);
7029  }
7030  /**
7031  * value for edit interface
7032  * @param bool $onlyopt if true only optionnal attributes are displayed
7033  */
7034  function editbodycard($target = "_self", $ulink = true, $abstract = false, $onlyopt = false)
7035  {
7036  include_once ("FDL/editutil.php");
7037  include_once ("FDL/Class.SearchDoc.php");
7038 
7039  $docid = $this->id; // document to edit
7040  // ------------------------------------------------------
7041  // new or modify ?
7042  if ($docid == 0) {
7043  // new document
7044  if ($this->fromid > 0) {
7045  $cdoc = $this->getFamDoc();
7046  $this->lay->Set("title", sprintf(_("new %s") , $cdoc->title));
7047  }
7048  } else {
7049  // when modification
7050  if (!$this->isAlive()) $action->ExitError(_("document not referenced"));
7051  $this->lay->Set("title", $this->title);
7052  }
7053  $this->lay->Set("id", $docid);
7054  $this->lay->Set("classid", $this->fromid);
7055  // search inline help
7056  $s = new SearchDoc($this->dbaccess, "HELPPAGE");
7057  $s->addFilter("help_family='%d'", $this->fromid);
7058  $help = $s->search();
7059  $helpid = false;
7060  $helpattr = array();
7061  if ($s->count() > 0) {
7062  $helpid = $help[0]["id"];
7063  $helpattr = $this->_val2array($help[0]["help_sec_key"]);
7064  }
7065  // ------------------------------------------------------
7066  // Perform SQL search for doc attributes
7067  // ------------------------------------------------------
7068  $frames = array();
7069  $listattr = $this->GetInputAttributes($onlyopt);
7070 
7071  $nattr = count($listattr); // number of attributes
7072  $k = 0; // number of frametext
7073  $v = 0; // number of value in one frametext
7074  $currentFrameId = "";
7075  $currentFrameText = "";
7076  $currentFrame = null;
7077  $changeframe = false;
7078  $ih = 0; // index for hidden values
7079  $thidden = array();
7080  $tableframe = array();
7081  $ttabs = array();
7082 
7083  $iattr = 0;
7084 
7085  foreach ($listattr as $i => $attr) {
7086  $iattr++;
7087  // Compute value elements
7088  if ($docid > 0) $value = $this->GetValue($attr->id);
7089  else {
7090  $value = $this->GetValue($attr->id);
7091  // $value = $this->GetValueMethod($this->GetValue($listattr[$i]->id));
7092 
7093  }
7094  if (!$attr->fieldSet) {
7095  addWarningMsg(sprintf(_("unknow set for attribute %s %s") , $attr->id, $attr->getLabel()));
7096  continue;
7097  }
7098  $frametpl = $attr->fieldSet->getOption("edittemplate");
7099 
7100  if ($currentFrameId != $attr->fieldSet->id) {
7101  if ($frametpl) {
7102  $changeframe = true;
7103  $currentFrameId = $attr->fieldSet->id;
7104  $currentFrame = $attr->fieldSet;
7105  if ($currentFrame->getOption("vlabel") == "none") $currentFrameText = '';
7106  else $currentFrameText = mb_ucfirst($currentFrame->GetLabel());
7107  $v++;
7108  } elseif ($currentFrameId != "") $changeframe = true;
7109  }
7110  if ($changeframe) { // to generate final frametext
7111  $changeframe = false;
7112  if ($v > 0) { // one value detected
7113  $frames[$k]["frametext"] = $currentFrameText;
7114  $frames[$k]["frameid"] = $currentFrameId;
7115  $frames[$k]["tag"] = "";
7116  $frames[$k]["TAB"] = false;
7117  $frames[$k]["edittpl"] = ($frametpl != "");
7118  $frames[$k]["zonetpl"] = ($frametpl != "") ? sprintf("[ZONE FDL:EDITTPL?id=%d&famid=%d&zone=%s]", $this->id, $this->fromid, $frametpl) : '';
7119 
7120  $oaf = $this->getAttribute($currentFrameId);
7121  $frames[$k]["bgcolor"] = $oaf ? $oaf->getOption("bgcolor", false) : false;
7122  if ($currentFrame && ($currentFrame->fieldSet->id != "") && ($currentFrame->fieldSet->id != "FIELD_HIDDENS")) {
7123  $frames[$k]["tag"] = "TAG" . $currentFrame->fieldSet->id;
7124  $frames[$k]["TAB"] = true;
7125  $ttabs[$currentFrame->fieldSet->id] = array(
7126  "tabid" => $currentFrame->fieldSet->id,
7127  "tabtitle" => ($currentFrame->fieldSet->getOption("vlabel") == "none") ? '&nbsp;' : mb_ucfirst($currentFrame->fieldSet->getLabel())
7128  );
7129  }
7130  $frames[$k]["TABLEVALUE"] = "TABLEVALUE_$k";
7131  $this->lay->SetBlockData($frames[$k]["TABLEVALUE"], $tableframe);
7132  unset($tableframe);
7133  $tableframe = array();
7134  $k++;
7135  }
7136  $v = 0;
7137  }
7138  if (!$frametpl) {
7139  //------------------------------
7140  // Set the table value elements
7141  $currentFrameId = $listattr[$i]->fieldSet->id;
7142  $currentFrame = $listattr[$i]->fieldSet;
7143  if ($currentFrame->getOption("vlabel") == "none") $currentFrameText = '';
7144  else $currentFrameText = mb_ucfirst($currentFrame->GetLabel());
7145  if (($listattr[$i]->mvisibility == "H") || ($listattr[$i]->mvisibility == "R")) {
7146  // special case for hidden values
7147  $thidden[$ih]["hname"] = "_" . $listattr[$i]->id;
7148  $thidden[$ih]["hid"] = $listattr[$i]->id;
7149  if (($value == "") && ($this->id == 0)) $thidden[$ih]["hvalue"] = GetHttpVars($listattr[$i]->id);
7150  else $thidden[$ih]["hvalue"] = chop(htmlentities($value, ENT_COMPAT, "UTF-8"));
7151 
7152  $thidden[$ih]["inputtype"] = getHtmlInput($this, $listattr[$i], $value, "", "", true);
7153  $ih++;
7154  } else {
7155  $tableframe[$v]["value"] = chop(htmlentities($value, ENT_COMPAT, "UTF-8"));
7156  $label = $listattr[$i]->getLabel();
7157  $tableframe[$v]["attrid"] = $listattr[$i]->id;
7158  $tableframe[$v]["name"] = mb_ucfirst($label);
7159 
7160  if ($listattr[$i]->needed) $tableframe[$v]["labelclass"] = "FREEDOMLabelNeeded";
7161  else $tableframe[$v]["labelclass"] = "FREEDOMLabel";
7162  $elabel = $listattr[$i]->getoption("elabel");
7163  $elabel = str_replace("'", "&rsquo;", $elabel);
7164  $tableframe[$v]["elabel"] = mb_ucfirst(str_replace('"', "&rquot;", $elabel));
7165  $tableframe[$v]["helpid"] = $helpid;
7166  $tableframe[$v]["ehelp"] = ($helpid != false) && (in_array($listattr[$i]->id, $helpattr));
7167 
7168  $tableframe[$v]["multiple"] = ($attr->getOption("multiple") == "yes") ? "true" : "false";
7169  $tableframe[$v]["atype"] = $attr->type;
7170  $tableframe[$v]["name"] = mb_ucfirst($label);
7171  $tableframe[$v]["classback"] = ($attr->usefor == "O") ? "FREEDOMOpt" : "FREEDOMBack1";
7172  //$tableframe[$v]["name"]=$action->text($label);
7173  $tableframe[$v]["SINGLEROW"] = true;
7174 
7175  $vlabel = $listattr[$i]->getOption("vlabel");
7176  if ((($listattr[$i]->type == "array") && ($vlabel != 'left')) || (($listattr[$i]->type == "htmltext") && ($vlabel != 'left')) || ($vlabel == 'up') || ($vlabel == 'none')) $tableframe[$v]["SINGLEROW"] = false;
7177 
7178  $tableframe[$v]["viewlabel"] = (($listattr[$i]->type != "array") && ($vlabel != 'none'));
7179  $edittpl = $listattr[$i]->getOption("edittemplate");
7180  if ($edittpl) {
7181  if ($edittpl == "none") {
7182  unset($tableframe[$v]);
7183  } else {
7184  if ($this->getZoneOption($edittpl) == 'S') {
7185  $tableframe[$v]["SINGLEROW"] = false;
7186  $tableframe[$v]["viewlabel"] = false;
7187  }
7188  $tableframe[$v]["inputtype"] = sprintf("[ZONE FDL:EDITTPL?id=%d&famid=%d&zone=%s]", $this->id, $this->fromid, $edittpl);
7189  }
7190  } else {
7191  $tableframe[$v]["inputtype"] = getHtmlInput($this, $listattr[$i], $value);
7192  }
7193  $v++;
7194  }
7195  }
7196  }
7197  // Out
7198  if ($v > 0) { // latest fieldset
7199  $frames[$k]["frametext"] = $currentFrameText;
7200  $frames[$k]["frameid"] = $currentFrameId;
7201  $frames[$k]["TABLEVALUE"] = "TABLEVALUE_$k";
7202  $frames[$k]["tag"] = "";
7203  $frames[$k]["TAB"] = false;
7204  $frames[$k]["edittpl"] = ($frametpl != "");
7205  $frames[$k]["zonetpl"] = ($frametpl != "") ? sprintf("[ZONE FDL:EDITTPL?id=%d&famid=%d&zone=%s]", $this->id, $this->fromid, $frametpl) : '';
7206 
7207  $oaf = $this->getAttribute($currentFrameId);
7208  $frames[$k]["bgcolor"] = $oaf ? $oaf->getOption("bgcolor", false) : false;
7209  if (($currentFrame->fieldSet->id != "") && ($currentFrame->fieldSet->id != "FIELD_HIDDENS")) {
7210  $frames[$k]["tag"] = "TAG" . $currentFrame->fieldSet->id;
7211  $frames[$k]["TAB"] = true;
7212  $ttabs[$currentFrame->fieldSet->id] = array(
7213  "tabid" => $currentFrame->fieldSet->id,
7214  "tabtitle" => ($currentFrame->fieldSet->getOption("vlabel") == "none") ? '&nbsp;' : mb_ucfirst($currentFrame->fieldSet->getLabel())
7215  );
7216  }
7217  $this->lay->SetBlockData($frames[$k]["TABLEVALUE"], $tableframe);
7218  }
7219  $this->lay->SetBlockData("HIDDENS", $thidden);
7220  $this->lay->SetBlockData("TABLEBODY", $frames);
7221  $this->lay->SetBlockData("TABS", $ttabs);
7222  $this->lay->Set("ONETAB", count($ttabs) > 0);
7223  $this->lay->Set("fromid", $this->fromid);
7224  $this->lay->Set("docid", $this->id);
7225  if (count($ttabs) > 0) {
7226  $this->lay->Set("firsttab", false);
7227  $ut = $this->getUtag("lasttab");
7228  if ($ut) $firstopen = $ut->comment; // last memo tab
7229  else $firstopen = false;
7230 
7231  foreach ($ttabs as $k => $v) {
7232  $oa = $this->getAttribute($k);
7233  if ($oa->getOption("firstopen") == "yes") $this->lay->Set("firsttab", $k);
7234  if ($firstopen == $oa->id) $this->lay->Set("firsttab", $k);
7235  }
7236  }
7237  }
7238  /**
7239  * create input fields for attribute document
7240  * @param bool $withtd set to false if don't wan't <TD> tag in the middle
7241  */
7242  final public function editattr($withtd = true)
7243  {
7244 
7245  include_once ("FDL/editutil.php");
7246  $listattr = $this->GetNormalAttributes();
7247  // each value can be instanced with L_<ATTRID> for label text and V_<ATTRID> for value
7248  foreach ($listattr as $k => $v) {
7249  //------------------------------
7250  // Set the table value elements
7251  $value = chop($this->GetValue($v->id));
7252  if ($v->mvisibility == "R") $v->mvisibility = "H"; // don't see in edit mode
7253  $this->lay->Set("V_" . strtoupper($v->id) , getHtmlInput($this, $v, $value, "", "", (!$withtd)));
7254  if ($v->needed == "Y") $this->lay->Set("L_" . strtoupper($v->id) , "<B>" . $v->getLabel() . "</B>");
7255  else $this->lay->Set("L_" . strtoupper($v->id) , $v->getLabel());
7256  $this->lay->Set("W_" . strtoupper($v->id) , ($v->mvisibility != "H"));
7257  }
7258 
7259  $listattr = $this->GetFieldAttributes();
7260  // each value can be instanced with L_<ATTRID> for label text and V_<ATTRID> for value
7261  foreach ($listattr as $k => $v) {
7262  $this->lay->Set("L_" . strtoupper($v->id) , $v->getLabel());
7263  }
7264 
7265  $this->setFamidInLayout();
7266  }
7267 
7268  final public function setFamidInLayout()
7269  {
7270  // add IDFAM_ attribute in layout
7271  global $tFamIdName;
7272 
7273  if (!isset($tFamIdName)) getFamIdFromName($this->dbaccess, "-");
7274 
7275  reset($tFamIdName);
7276  foreach ($tFamIdName as $k => $v) {
7277  $this->lay->set("IDFAM_$k", $v);
7278  }
7279  }
7280  /**
7281  * get vault file name or server path of filename
7282  * @param string $idAttr identificator of file attribute
7283  * @param bool $path false return original file name (basename) , true the real path
7284  * @param int $index in case of array of files
7285  * @return string the file name of the attribute
7286  */
7287  final public function vault_filename($attrid, $path = false, $index = - 1)
7288  {
7289  if ($index == - 1) $fileid = $this->getValue($attrid);
7290  else $fileid = $this->getTValue($attrid, '', $index);
7291  return $this->vault_filename_fromvalue($fileid, $path);
7292  }
7293  /**
7294  * get vault file name or server path of filename
7295  * @param string $fileid value of file attribute
7296  * @param bool $path false return original file name (basename) , true the real path
7297  * @return string the file name of the attribute
7298  */
7299  final public function vault_filename_fromvalue($fileid, $path = false)
7300  {
7301  $fname = "";
7302  if (preg_match(PREGEXPFILE, $fileid, $reg)) {
7303  // reg[1] is mime type
7304  $vf = newFreeVaultFile($this->dbaccess);
7305  if ($vf->Show($reg[2], $info) == "") {
7306  if ($path) $fname = $info->path;
7307  else $fname = $info->name;
7308  }
7309  }
7310  return $fname;
7311  }
7312  /**
7313  * get vault file name or server path of filename
7314  * @param NormalAttribute $idAttr identificator of file attribute
7315  * @param bool false return original file name (basename) , true the real path
7316  * @return array of properties :
7317  [0]=>
7318  [name] => TP_Users.pdf
7319  [size] => 179435
7320  [public_access] =>
7321  [mime_t] => PDF document, version 1.4
7322  [mime_s] => application/pdf
7323  [cdate] => 24/12/2010 11:44:36
7324  [mdate] => 24/12/2010 11:44:41
7325  [adate] => 25/03/2011 08:13:34
7326  [teng_state] => 1
7327  [teng_lname] => pdf
7328  [teng_vid] => 15
7329  [teng_comment] =>
7330  [path] => /var/www/eric/vaultfs/1/16.pdf
7331  [vid] => 16
7332  */
7333  final public function vault_properties(NormalAttribute $attr)
7334  {
7335  if ($attr->inArray()) $fileids = $this->getTValue($attr->id);
7336  else $fileids[] = $this->getValue($attr->id);
7337 
7338  $tinfo = array();
7339  foreach ($fileids as $k => $fileid) {
7340  if (preg_match(PREGEXPFILE, $fileid, $reg)) {
7341  // reg[1] is mime type
7342  $vf = newFreeVaultFile($this->dbaccess);
7343  if ($vf->Show($reg[2], $info) == "") {
7344  $tinfo[$k] = get_object_vars($info);
7345  $tinfo[$k]["vid"] = $reg[2];
7346  }
7347  }
7348  }
7349 
7350  return $tinfo;
7351  }
7352  /**
7353  * return a property of vault file value
7354  *
7355  * @param string $filesvalue the file value : like application/pdf|12345
7356  * @param string $key one of property id_file, name, size, public_access, mime_t, mime_s, cdate, mdate, adate, teng_state, teng_lname, teng_vid, teng_comment, path
7357  * @return string value of property or array of all properties if no key
7358  */
7359  final public function getFileInfo($filesvalue, $key = "")
7360  {
7361  if (!is_string($filesvalue)) return false;
7362  if (preg_match(PREGEXPFILE, $filesvalue, $reg)) {
7363  include_once ("FDL/Lib.Vault.php");
7364  $vid = $reg[2];
7365  $info = vault_properties($vid);
7366  if (!$info) return false;
7367  if ($key != "") {
7368  if (isset($info->$key)) return $info->$key;
7369  else return sprintf(_("unknow %s file property") , $key);
7370  } else {
7371  return get_object_vars($info);
7372  }
7373  }
7374  }
7375  /**
7376  *
7377  * @param string &$xml content xml (empty if $outfile is not empty
7378  * @param boolean $withfile include files in base64 encoded
7379  * @param string $outfile if not empty means content is put into this file
7380  * @param boolean $flat set to true if don't want structure
7381  * @param array $exportAttribute to export only a part of attributes
7382  * @return string error message (empty if no error)
7383  */
7384  public function exportXml(&$xml, $withfile = false, $outfile = "", $wident = true, $flat = false, $exportAttributes = array())
7385  {
7386 
7387  $lay = new Layout(getLayoutFile("FDL", "exportxml.xml"));
7388  //$lay=&$this->lay;
7389  $lay->set("famname", strtolower($this->fromname));
7390  $lay->set("id", ($wident ? $this->id : ''));
7391  $lay->set("name", $this->name);
7392  $lay->set("revision", $this->revision);
7393  $lay->set("version", $this->getVersion());
7394  $lay->set("state", $this->getState());
7395  $lay->set("title", str_replace(array(
7396  "&",
7397  '<',
7398  '>'
7399  ) , array(
7400  "&amp;",
7401  '&lt;',
7402  '&gt;'
7403  ) , $this->getTitle()));
7404  $lay->set("mdate", strftime("%FT%X", $this->revdate));
7405  $lay->set("flat", $flat);
7406  $la = $this->GetFieldAttributes();
7407  $level1 = array();
7408 
7409  foreach ($la as $k => $v) {
7410  if ((!$v) || ($v->getOption("autotitle") == "yes") || ($v->usefor == 'Q')) unset($la[$k]);
7411  }
7412  $option->withFile = $withfile;
7413  $option->outFile = $outfile;
7414  $option->withIdentificator = $wident;
7415  $option->flat = $flat;
7416  $option->exportAttributes = $exportAttributes;
7417 
7418  foreach ($la as $k => & $v) {
7419  if (($v->id != "FIELD_HIDDENS") && ($v->type == 'frame' || $v->type == "tab") && ((!$v->fieldSet) || $v->fieldSet->id == "FIELD_HIDDENS")) {
7420  $level1[] = array(
7421  "level" => $v->getXmlValue($this, $option)
7422  );
7423  } else {
7424  // if ($v) $tax[]=array("tax"=>$v->getXmlSchema());
7425 
7426  }
7427  }
7428  $lay->setBlockData("top", $level1);
7429  if ($outfile) {
7430  if ($withfile) {
7431  $xmlcontent = $lay->gen();
7432  $fo = fopen($outfile, "w");
7433  $pos = strpos($xmlcontent, "[FILE64");
7434  $bpos = 0;
7435  while ($pos !== false) {
7436  if (fwrite($fo, substr($xmlcontent, $bpos, $pos - $bpos))) {
7437  $bpos = strpos($xmlcontent, "]", $pos) + 1;
7438 
7439  $filepath = substr($xmlcontent, $pos + 8, ($bpos - $pos - 9));
7440  /* If you want to encode a large file, you should encode it in chunks that
7441  are a multiple of 57 bytes. This ensures that the base64 lines line up
7442  and that you do not end up with padding in the middle. 57 bytes of data
7443  fills one complete base64 line (76 == 57*4/3):*/
7444  $ff = fopen($filepath, "r");
7445  $size = 6 * 1024 * 57;
7446  while ($buf = fread($ff, $size)) {
7447  fwrite($fo, base64_encode($buf));
7448  }
7449  $pos = strpos($xmlcontent, "[FILE64", $bpos);
7450  } else {
7451  $err = sprintf(_("exportXml : cannot write file %s") , $outfile);
7452  $pos = false;
7453  }
7454  }
7455  if ($err == "") fwrite($fo, substr($xmlcontent, $bpos));
7456  fclose($fo);
7457  } else {
7458  if (file_put_contents($outfile, $lay->gen()) === false) {
7459  $err = sprintf(_("exportXml : cannot write file %s") , $outfile);
7460  }
7461  }
7462  } else {
7463  $xml = $lay->gen();
7464  return $err;
7465  }
7466  return $err;
7467  }
7468  // =====================================================================================
7469  // ================= Methods use for XML ======================
7470  final public function toxml($withdtd = false, $id_doc = "")
7471  {
7472 
7473  global $action;
7475 
7476  $docid = intval($this->id);
7477  if ($id_doc == "") {
7478  $id_doc = $docid;
7479  }
7480 
7481  $title = $this->title;
7483  $dbaccess = $action->GetParam("FREEDOM_DB");
7484  $fam_doc = new_Doc($this->dbaccess, $this->fromid);
7485  $name = str_replace(" ", "_", $fam_doc->title);
7486 
7487  if ($withdtd == true) {
7488  $dtd = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>";
7489  $dtd.= "<!DOCTYPE $name [";
7490  $dtd.= $this->todtd();
7491  $dtd.= "]>";
7492  } else {
7493  $dtd = "";
7494  }
7495 
7496  $this->lay = new Layout("FDL/Layout/viewxml.xml", $action);
7497  $this->lay->Set("DTD", $dtd);
7498  $this->lay->Set("NOM_FAM", $name);
7499  $this->lay->Set("id_doc", $id_doc);
7500  $this->lay->Set("TITRE", $title);
7501  $this->lay->Set("ID_FAM", $fam_doc->name);
7502  $this->lay->Set("revision", $this->revision);
7503  $this->lay->Set("revdate", $this->revdate);
7504  //$this->lay->Set("IDOBJECT",$docid);
7505  //$this->lay->Set("IDFAM",$fromid);
7506  //$idfam=$fam_doc->classname;
7507  //$this->lay->Set("TYPEOBJECT",$doctype);
7508  ////debut
7509  $listattr = $this->GetNormalAttributes();
7510 
7511  $frames = array();
7512 
7513  $nattr = count($listattr); // attributes list count
7514  $k = 0; // number of frametext
7515  $v = 0; // number of value in one frametext
7516  $currentFrameId = "";
7517 
7518  $changeframe = false; // is true when need change frame
7519  $tableframe = array();
7520 
7521  $iattr = 0;
7522 
7523  foreach ($listattr as $i => $attr) {
7524  $iattr++;
7525 
7526  if ((chop($listattr[$i]->id) != "") && ($listattr[$i]->id != "FIELD_HIDDENS")) {
7527  //------------------------------
7528  // Compute value elements
7529  if ($currentFrameId != $listattr[$i]->fieldSet->id) {
7530  if ($currentFrameId != "") $changeframe = true;
7531  }
7532  //------------------------------
7533  // change frame if needed
7534  if ( // to generate fiedlset
7535  $changeframe) {
7536  $changeframe = false;
7537  if ($v > 0) // one value detected
7538  {
7539 
7540  $frames[$k]["FIELD"] = $currentFrameId;
7541  $frames[$k]["ARGUMENT"] = "ARGUMENT_$k";
7542 
7543  $this->lay->SetBlockData($frames[$k]["ARGUMENT"], $tableframe);
7544  $frames[$k]["nom_fieldset"] = $this->GetLabel($currentFrameId);
7545  unset($tableframe);
7546  $tableframe = array();
7547  $k++;
7548  }
7549  $v = 0;
7550  }
7551  // Set the table value elements
7552  if (($iattr <= $nattr) && ($this->Getvalue($i) != "")) {
7553  $attrtype_idoc = false;
7554  $attrtype_list = false;
7555 
7556  if (strstr($listattr[$i]->type, "textlist") != false) {
7557  $attrtype_list = true;
7558  }
7559  if ((strstr($listattr[$i]->type, "idoclist")) != false) {
7560  $attrtype_list = true;
7561  $attrtype_idoc = true;
7562  }
7563  if ((strstr($listattr[$i]->type, "idoc")) != false) {
7564  $attrtype_idoc = true;
7565  }
7566  if ($listattr[$i]->inArray()) {
7567  $attrtype_list = true;
7568  }
7569 
7570  if ($attrtype_list) {
7571  // $value=htmlspecialchars($this->GetValue($i));
7572  $value = $this->GetValue($i);
7573  $textlist = $this->_val2array($value);
7574 
7575  while ($text = each($textlist)) {
7576  $currentFrameId = $listattr[$i]->fieldSet->id;
7577  $tableframe[$v]["id"] = $listattr[$i]->id;
7578  if ($attrtype_idoc) {
7579  $tableframe[$v]["value"] = base64_decode($text[1]);
7580  $tableframe[$v]["type"] = "idoc";
7581  } else {
7582  $tableframe[$v]["value"] = $text[1];
7583  $tableframe[$v]["type"] = base64_encode($listattr[$i]->type);
7584  }
7585  $tableframe[$v]["labelText"] = (str_replace(array(
7586  "%",
7587  "\""
7588  ) , array(
7589  "",
7590  "\\\""
7591  ) , $listattr[$i]->getLabel()));
7592  //$tableframe[$v]["type"]=$listattr[$i]->type;
7593  //$tableframe[$v]["visibility"]=$listattr[$i]->visibility;
7594  //$tableframe[$v]["needed"]=$listattr[$i]->needed;
7595  $v++;
7596  }
7597  } else {
7598 
7599  if ($attrtype_idoc) {
7600  $value = base64_decode($this->GetValue($i));
7601  $tableframe[$v]["type"] = "idoc";
7602  //printf($value);
7603 
7604  } else {
7605  $value = htmlspecialchars($this->GetValue($i));
7606  $tableframe[$v]["type"] = base64_encode($listattr[$i]->type);
7607  }
7608 
7609  $currentFrameId = $listattr[$i]->fieldSet->id;
7610  $tableframe[$v]["id"] = $listattr[$i]->id;
7611  $tableframe[$v]["value"] = $value;
7612  $tableframe[$v]["labelText"] = addslashes($listattr[$i]->getLabel());
7613  //$tableframe[$v]["type"]=$listattr[$i]->type;
7614  //$tableframe[$v]["visibility"]=$listattr[$i]->visibility;
7615  //$tableframe[$v]["needed"]=$listattr[$i]->needed;
7616  $v++;
7617  }
7618  }
7619  }
7620  }
7621 
7622  if ($v > 0) // last fieldset
7623  {
7624 
7625  $frames[$k]["FIELD"] = $currentFrameId;
7626  $frames[$k]["ARGUMENT"] = "ARGUMENT_$k";
7627 
7628  $this->lay->SetBlockData($frames[$k]["ARGUMENT"], $tableframe);
7629  $frames[$k]["nom_fieldset"] = $this->GetLabel($currentFrameId);
7630  unset($tableframe);
7631  $tableframe = array();
7632  $tableimage = array();
7633  $k++;
7634  }
7635 
7636  $this->lay->SetBlockData("FIELDSET", $frames);
7637  return $this->lay->gen();
7638  }
7639 
7640  final public function todtd()
7641  {
7642 
7643  global $action;
7644  $this->lay = new Layout("FDL/Layout/viewdtd.xml", $action);
7645 
7646  $fam_doc = $this->getFamDoc();
7647  $name = str_replace(" ", "_", $fam_doc->title);
7648  $this->lay->Set("doctype", $this->doctype);
7649  $this->lay->Set("idfam", $this->fromid);
7650  $this->lay->Set("nom_fam", $name);
7651  $this->lay->Set("id_fam", $name);
7652 
7653  $listattr = $this->GetNormalAttributes();
7654 
7655  $frames = array();
7656 
7657  $nattr = count($listattr); // attributes list count
7658  $k = 0; // number of frametext
7659  $v = 0; // number of value in one frametext
7660  $currentFrameId = "";
7661 
7662  $changeframe = false; // is true when need change frame
7663  $needed = false;
7664  $tableattrs = array();
7665  $tablesetting = array();
7666  $iattr = 0;
7667 
7668  foreach ($listattr as $i => $attr) {
7669  $iattr++;
7670  //------------------------------
7671  // Compute value elements
7672  if ($currentFrameId != $listattr[$i]->fieldSet->id) {
7673  if ($currentFrameId != "") $changeframe = true;
7674  }
7675  //------------------------------
7676  // change frame if needed
7677  if ( // to generate fiedlset
7678  $changeframe) {
7679  $changeframe = false;
7680 
7681  if ($v > 0) // one value detected
7682  {
7683 
7684  $frames[$k]["name"] = $currentFrameId;
7685  $elements[$k]["name"] = $currentFrameId;
7686  if ($needed) {
7687  $elements[$k]["name"].= ", ";
7688  } else {
7689  $elements[$k]["name"].= "?, ";
7690  }
7691  $needed = false;
7692 
7693  $frames[$k]["ATTRIBUT_NAME"] = "ATTRIBUT_NAME_$k";
7694  $frames[$k]["ATTRIBUT_SETTING"] = "ATTRIBUT_SETTING_$k";
7695 
7696  $this->lay->SetBlockData($frames[$k]["ATTRIBUT_NAME"], $tableattrs);
7697 
7698  $this->lay->SetBlockData($frames[$k]["ATTRIBUT_SETTING"], $tablesetting);
7699  unset($tableattrs);
7700  unset($tablesetting);
7701  $tableattrs = array();
7702  $tablesetting = array();
7703 
7704  $k++;
7705  }
7706  $v = 0;
7707  }
7708  // Set the table value elements
7709  if ($iattr <= $nattr) {
7710 
7711  $currentFrameId = $listattr[$i]->fieldSet->id;
7712  $tablesetting[$v]["name_attribut"] = $listattr[$i]->id;
7713  $tablesetting[$v]["labelText"] = addslashes(str_replace("%", "", $listattr[$i]->getLabel()));
7714  $tablesetting[$v]["type"] = base64_encode($listattr[$i]->type);
7715  $tablesetting[$v]["visibility"] = $listattr[$i]->visibility;
7716  if ($listattr[$i]->needed) {
7717  $needed = true;
7718  }
7719 
7720  if ($v == 0) {
7721  $insert = $listattr[$i]->id;
7722  if ($listattr[$i]->type == "textlist") {
7723  if ($listattr[$i]->needed) {
7724  $insert.= "+";
7725  $tableattrs[$v]["name_attribut"] = $insert;
7726  } else {
7727  $insert.= "*";
7728  $tableattrs[$v]["name_attribut"] = $insert;
7729  }
7730  } else {
7731  if ($listattr[$i]->needed) {
7732  $tableattrs[$v]["name_attribut"] = $insert;
7733  } else {
7734  $tableattrs[$v]["name_attribut"] = ($insert . "?");
7735  }
7736  }
7737  } else {
7738  $insert = (", " . $listattr[$i]->id);
7739  if ($listattr[$i]->type == "textlist") {
7740  if ($listattr[$i]->needed) {
7741  $insert.= "+";
7742  } else {
7743  $insert.= "*";
7744  }
7745  $tableattrs[$v]["name_attribut"] = $insert;
7746  } else {
7747  if ($listattr[$i]->needed) {
7748  $tableattrs[$v]["name_attribut"] = $insert;
7749  } else {
7750  $tableattrs[$v]["name_attribut"] = ($insert . "?");
7751  }
7752  }
7753  }
7754  $v++;
7755  }
7756  }
7757 
7758  if ($v > 0) // last fieldset
7759  {
7760  $frames[$k]["name"] = $currentFrameId;
7761  if ($needed) {
7762  $elements[$k]["name"] = $currentFrameId;
7763  } else {
7764  $elements[$k]["name"] = ($currentFrameId . "?");
7765  }
7766  $needed = false;
7767  $frames[$k]["ATTRIBUT_NAME"] = "ATTRIBUT_NAME_$k";
7768  $frames[$k]["ATTRIBUT_SETTING"] = "ATTRIBUT_SETTING_$k";
7769  $this->lay->SetBlockData($frames[$k]["ATTRIBUT_NAME"], $tableattrs);
7770 
7771  $this->lay->SetBlockData($frames[$k]["ATTRIBUT_SETTING"], $tablesetting);
7772  unset($tableattrs);
7773  unset($tablesetting);
7774  $tableattrs = array();
7775  $tablesetting = array();
7776 
7777  $k++;
7778  }
7779 
7780  $this->lay->SetBlockData("FIELDSET", $frames);
7781  $this->lay->SetBlockData("ELEMENT", $elements);
7782  return $this->lay->gen();
7783  }
7784  /**
7785  * return possible dynamic title
7786  * this method can be redefined in child if the title is variable by other parameters than containt
7787  */
7788  function getSpecTitle()
7789  {
7790  return $this->title;
7791  }
7792 
7793  final public function refreshDocTitle($nameId, $nameTitle)
7794  {
7795  // gettitle(D,SI_IDSOC):SI_SOCIETY,SI_IDSOC
7796  $this->AddParamRefresh("$nameId", "$nameTitle");
7797  $doc = new_Doc($this->dbaccess, $this->getValue($nameId));
7798  if ($doc->isAlive()) $this->setValue($nameTitle, $doc->title);
7799  else {
7800  // suppress
7801  if (!$doc->isAffected()) $this->deleteValue($nameId);
7802  }
7803  }
7804  /**
7805  * get image emblem for the doc like lock/nowrite
7806  * @return string the url of the image
7807  */
7808  function getEmblem($size = null)
7809  {
7810  global $action;
7811  if ($this->confidential > 0) return $action->getImageUrl("confidential.gif", true, $size);
7812  else if ($this->locked == - 1) return $action->getImageUrl("revised.png", true, $size);
7813  else if ($this->lockdomainid > 0) {
7814  if ($this->locked > 0) {
7815  if ((abs($this->locked) == $this->userid)) return $action->getImageUrl("lockorange.png", true, $size);
7816  else return $action->getImageUrl("lockred.png", true, $size);
7817  } else return $action->getImageUrl("lockorange.png", true, $size);
7818  } else if ($this->allocated == $this->userid) return $action->getImageUrl("lockblue.png", true, $size);
7819  else if ((abs($this->locked) == $this->userid)) return $action->getImageUrl("lockgreen.png", true, $size);
7820  else if ($this->locked != 0) return $action->getImageUrl("lockred.png", true, $size);
7821  else if ($this->archiveid != 0) return $action->getImageUrl("archive.png", true, $size);
7822  else if ($this->control("edit") != "") return $action->getImageUrl("nowrite.png", true, $size);
7823  else return $action->getImageUrl("1x1.gif");
7824  }
7825  /**
7826  * use only for paramRefresh in attribute definition of a family
7827  */
7828  function nothing($a = "", $b = "", $c = "")
7829  {
7830  return "";
7831  }
7832  /**
7833  * return parameter value
7834  * @param string parameter
7835  * @param string default return value
7836  * @return string returns parameter value ou default value
7837  */
7838  final public function getParam($param, $defv = "")
7839  {
7840  return getParam($param, $defv);
7841  }
7842  //----------------------------------------------------------------------
7843  // USUAL METHODS USE FOR CALCULATED ATTRIBUTES OR FUNCTION SEARCHES
7844  //----------------------------------------------------------------------
7845  // ALL THESE METHODS NAME MUST BEGIN WITH 'GET'
7846 
7847  /**
7848  * return title of document in latest revision
7849  * @param string $id identificator of document
7850  * @param string $def default value if document not found
7851  */
7852  final public function getLastTitle($id = "-1", $def = "")
7853  {
7854  return $this->getTitle($id, $def, true);
7855  }
7856  /**
7857  * return title of document
7858  * @param string $id identificator of document
7859  * @param string $def default value if document not found
7860  * @param boolean $latest search title in latest revision
7861  * @see Doc::getSpecTitle()
7862  */
7863  final public function getTitle($id = "-1", $def = "", $latest = false)
7864  {
7865  if (is_array($id)) return $def;
7866  if ($id == "") return $def;
7867  if ($id == "-1") {
7868  if ($this->locked != - 1 || (!$latest)) {
7869  if ($this->isConfidential()) return _("confidential document");
7870  return $this->getSpecTitle();
7871  } else {
7872  // search latest
7873  $id = $this->latestId();
7874  $lastId = $id;
7875  }
7876  }
7877  if ((strpos($id, "\n") !== false) || (strpos($id, "<BR>") !== false)) {
7878  $tid = explode("\n", str_replace("<BR>", "\n", $id));
7879  $ttitle = array();
7880  foreach ($tid as $idone) {
7881  $ttitle[] = $this->getTitle($idone, $def, $latest);
7882  }
7883  return implode("\n", $ttitle);
7884  } else {
7885  if (!is_numeric($id)) $id = getIdFromName($this->dbaccess, $id);
7886  if ($id > 0) {
7887  $t = getTDoc($this->dbaccess, $id, array() , array(
7888  "title",
7889  "doctype",
7890  "locked",
7891  "initid"
7892  ));
7893  if ($latest && ($t["locked"] == - 1)) {
7894  if ($lastId != $id) {
7895  $id = getLatestDocId($this->dbaccess, $t["initid"]);
7896  $t = getTDoc($this->dbaccess, $id, array() , array(
7897  "title",
7898  "doctype",
7899  "locked"
7900  ));
7901  }
7902  }
7903  if ($t) {
7904  if ($t["doctype"] == 'C') return getFamTitle($t);
7905  return $t["title"];
7906  }
7907  return " "; // delete title
7908 
7909  }
7910  }
7911  return $def;
7912  }
7913  /**
7914  * Same as ::getTitle()
7915  * the < > characters as replace by entities
7916  */
7917  function getHTMLTitle($id = "-1", $def = "", $latest = false)
7918  {
7919  $t = $this->getTitle($id, $def, $latest);
7920  $t = str_replace("&", "&amp;", $t);
7921  return str_replace(array(
7922  "<",
7923  ">"
7924  ) , array(
7925  "&lt;",
7926  "&gt;"
7927  ) , $t);
7928  }
7929  /**
7930  * return the today date with european format DD/MM/YYYY
7931  * @param int $daydelta to have the current date more or less day (-1 means yesterday, 1 tomorrow)
7932  * @param int $dayhour hours of day
7933  * @param int $daymin minutes of day
7934  * @param bool $getlocale whether to return locale date or not
7935  * @return string YYYY-MM-DD or DD/MM/YYYY (depend of CORE_LCDATE parameter) or locale date
7936  */
7937  public static function getDate($daydelta = 0, $dayhour = "", $daymin = "", $getlocale = false)
7938  {
7939  $delta = abs(intval($daydelta));
7940  if ($daydelta > 0) {
7941  $nd = strtotime("+$delta day");
7942  } else if ($daydelta < 0) {
7943  $nd = strtotime("-$delta day");
7944  } else {
7945  $nd = time();
7946  }
7947  $isIsoDate = (getLcdate() == "iso");
7948  if ($dayhour !== "") {
7949  $delta = abs(intval($dayhour));
7950  if ($dayhour > 0) {
7951  $nd = strtotime("+$delta hour", $nd);
7952  } else if ($dayhour < 0) {
7953  $nd = strtotime("-$delta hour", $nd);
7954  }
7955  $delta = abs(intval($daymin));
7956  if ($daymin > 0) {
7957  $nd = strtotime("+$delta min", $nd);
7958  } else if ($daymin < 0) {
7959  $nd = strtotime("-$delta min", $nd);
7960  }
7961 
7962  if ($getlocale) {
7963  return stringDateToLocaleDate(date("Y-m-d H:i", $nd));
7964  } else {
7965  if ($isIsoDate) return date("Y-m-d H:i", $nd);
7966  else return date("d/m/Y H:i", $nd);
7967  }
7968  } else {
7969  if ($getlocale) {
7970  return stringDateToLocaleDate(date("Y-m-d", $nd));
7971  } else {
7972  if ($isIsoDate) return date("Y-m-d", $nd);
7973  else return date("d/m/Y", $nd);
7974  }
7975  }
7976  }
7977  /**
7978  * return the today date and time with european format DD/MM/YYYY HH:MM
7979  * @param int $hourdelta to have the current date more or less hour (-1 means one hour before, 1 one hour after)
7980  * @param bool $second if true format DD/MM/YYYY HH:MM
7981  * @return string DD/MM/YYYY HH:MM
7982  */
7983  public static function getTimeDate($hourdelta = 0, $second = false)
7984  {
7985  $delta = abs(intval($hourdelta));
7986  if ((getLcdate() == "iso")) {
7987  if ($second) $format = "Y-m-d H:i:s";
7988  else $format = "Y-m-d H:i";
7989  } else {
7990  if ($second) $format = "d/m/Y H:i:s";
7991  else $format = "d/m/Y H:i";
7992  }
7993  if ($hourdelta > 0) {
7994  if (is_float($hourdelta)) {
7995  $dm = intval((abs($hourdelta) - $delta) * 60);
7996  return date($format, strtotime("+$delta hour $dm minute"));
7997  } else return date($format, strtotime("+$delta hour"));
7998  } else if ($hourdelta < 0) {
7999  if (is_float($hourdelta)) {
8000  $dm = intval((abs($hourdelta) - $delta) * 60);
8001  return date($format, strtotime("-$delta hour $dm minute"));
8002  } else return date($format, strtotime("-$delta hour"));
8003  }
8004  return date($format);
8005  }
8006  /**
8007  * return value of an attribute for the document referenced
8008  * @param int $docid document identificator
8009  * @param string $attrid attribute identificator
8010  * @param string def $def default return value
8011  * @param bool $latest always last revision of document
8012  */
8013  final public function getDocValue($docid, $attrid, $def = " ", $latest = false)
8014  {
8015  if (intval($docid) > 0) {
8016  $doc = new_Doc($this->dbaccess, $docid);
8017  if ($doc->isAlive()) {
8018  if ($latest && ($doc->locked == - 1)) {
8019  $ldocid = $doc->latestId();
8020  if ($ldocid != $doc->id) $doc = new_Doc($this->dbaccess, $ldocid);
8021  }
8022  return $doc->getRValue($attrid, $def, $latest);
8023  }
8024  }
8025  return "";
8026  }
8027  /**
8028  * return value of an property for the document referenced
8029  * @param int document identificator
8030  * @param string property identificator
8031  * @param bool $latest always last revision of document if true
8032  */
8033  final public function getDocProp($docid, $propid, $latest = false)
8034  {
8035  if (intval($docid) > 0) {
8036  if ($latest) $tdoc = getTDoc($this->dbaccess, $docid);
8037  else $tdoc = getLatestTDoc($this->dbaccess, $docid);
8038  return $tdoc[strtolower($propid) ];
8039  }
8040  return "";
8041  }
8042  /**
8043  * return the user last name
8044  * @param bool $withfirst if true compose first below last name
8045  * @return string
8046  */
8047  public static function getUserName($withfirst = false)
8048  {
8049  global $action;
8050  if ($withfirst) return $action->user->firstname . " " . $action->user->lastname;
8051  return $action->user->lastname;
8052  }
8053  /**
8054  * return the personn doc id conform to firstname & lastname of the user
8055  * @return int
8056  */
8057  public static function userDocId()
8058  {
8059  global $action;
8060 
8061  return $action->user->fid;
8062  }
8063  /**
8064  * alias for @see Doc:userDocId
8065  * @return int
8066  */
8067  public static function getUserId()
8068  {
8069  return Doc::userDocId();
8070  }
8071  /**
8072  * return system user id
8073  * @deprecated
8074  * @return int
8075  */
8076  public static function getWhatUserId()
8077  {
8078  global $action;
8080 
8081  return $action->user->id;
8082  }
8083  /**
8084  * return system user id
8085  * @return int
8086  */
8087  public static function getSystemUserId()
8088  {
8089  global $action;
8090  return $action->user->id;
8091  }
8092  /**
8093  * return a specific attribute of the current user document
8094  * @return int
8095  */
8096  final public function getMyAttribute($idattr)
8097  {
8098  $mydoc = new_Doc($this->dbaccess, $this->getUserId());
8099 
8100  return $mydoc->getValue($idattr);
8101  }
8102  /**
8103  * concatenate and format string
8104  * @param string $fmt like sprintf format
8105  * @param string parameters of string composition
8106  * @return string the composed string
8107  */
8108  function formatString($fmt)
8109  {
8110  $nargs = func_num_args();
8111  for ($ip = 0; $ip < $nargs; $ip++) {
8112  $var = func_get_arg($ip);
8113  }
8114  if ($nargs < 1) return "";
8115  $fmt = func_get_arg(0);
8116  $sp = array();
8117  for ($ip = 1; $ip < $nargs; $ip++) {
8118  if (gettype($var) != "array") {
8119  $sp[] = func_get_arg($ip);
8120  }
8121  }
8122  $r = vsprintf($fmt, $sp);
8123  return $r;
8124  }
8125 
8126  public function UpdateVaultIndex()
8127  {
8128  $dvi = new DocVaultIndex($this->dbaccess);
8129  $err = $dvi->DeleteDoc($this->id);
8130  $fa = $this->GetFileAttributes();
8131 
8132  $tvid = array();
8133  foreach ($fa as $aid => $oattr) {
8134  if ($oattr->inArray()) {
8135  $ta = $this->getTValue($aid);
8136  } else {
8137  $ta = array(
8138  $this->getValue($aid)
8139  );
8140  }
8141  foreach ($ta as $k => $v) {
8142  $vid = "";
8143  if (preg_match(PREGEXPFILE, $v, $reg)) {
8144  $vid = $reg[2];
8145  $tvid[$vid] = $vid;
8146  }
8147  }
8148  }
8149 
8150  foreach ($tvid as $k => $vid) {
8151  $dvi->docid = $this->id;
8152  $dvi->vaultid = $vid;
8153  $dvi->Add();
8154  }
8155  }
8156  // ===================
8157  // Timer Part
8158 
8159  /**
8160  * attach timer to a document
8161  * @param _TIMER &$timer the timer document
8162  * @param Doc &$origin the document which comes from the attachement
8163  * @return string error - empty if no error -
8164  */
8165  final public function attachTimer(&$timer, &$origin = null, $execdate = null)
8166  {
8167  $dyn = false;
8168  if ($execdate == null) {
8169  $dyn = trim(strtok($timer->getValue("tm_dyndate") , " "));
8170  if ($dyn) $execdate = $this->getValue($dyn);
8171  }
8172  if (method_exists($timer, 'attachDocument')) {
8173  $err = $timer->attachDocument($this, $origin, $execdate);
8174  if ($err == "") {
8175  if ($dyn) $this->addATag("DYNTIMER");
8176  $this->addComment(sprintf(_("attach timer %s [%d]") , $timer->title, $timer->id) , HISTO_NOTICE);
8177  $this->addLog("attachtimer", array(
8178  "timer" => $timer->id
8179  ));
8180  }
8181  } else {
8182  $err = sprintf(_("attachTimer : the timer parameter is not a document of TIMER family"));
8183  }
8184  return $err;
8185  }
8186  /**
8187  * unattach timer to a document
8188  * @param _TIMER &$timer the timer document
8189  * @param Doc &$origin if set unattach all timer which comes from this origin
8190  * @return string error - empty if no error -
8191  */
8192  final public function unattachTimer(&$timer)
8193  {
8194  if (method_exists($timer, 'unattachDocument')) {
8195  $err = $timer->unattachDocument($this);
8196  if ($err == "") {
8197  $this->addComment(sprintf(_("unattach timer %s [%d]") , $timer->title, $timer->id) , HISTO_NOTICE);
8198  $this->addLog("unattachtimer", array(
8199  "timer" => $timer->id
8200  ));
8201  }
8202  } else $err = sprintf(_("unattachTimer : the timer parameter is not a document of TIMER family"));
8203  return $err;
8204  }
8205 
8206  final public function resetDynamicTimers()
8207  {
8208  $tms = $this->getAttachedTimers();
8209  if (count($tms) == 0) {
8210  $this->delATag("DYNTIMER");
8211  } else {
8212  foreach ($tms as $k => $v) {
8213  $t = new_doc($this->dbaccess, $v["timerid"]);
8214  $this->unattachTimer($t);
8215  if ($t->isAlive()) {
8216  if ($v["originid"]) $ori = new_doc($this->dbaccess, $v["originid"]);
8217  else $ori = null;
8218  $this->attachTimer($t, $ori);
8219  }
8220  }
8221  }
8222  }
8223  /**
8224  * unattach timer to a document
8225  * @param _TIMER &$timer the timer document
8226  * @param Doc &$origin if set unattach all timer which comes from this origin
8227  * @return string error - empty if no error -
8228  */
8229  final public function unattachAllTimers(&$origin = null)
8230  {
8231  $timer = createTmpDoc($this->dbaccess, "TIMER");
8232  $err = $timer->unattachAllDocument($this, $origin, $c);
8233  if ($err == "" && $c > 0) {
8234  if ($origin) $this->addComment(sprintf(_("unattach %d timers associated to %s") , $c, $origin->title) , HISTO_NOTICE);
8235  else $this->addComment(sprintf(_("unattach all timers [%s]") , $c) , HISTO_NOTICE);
8236  $this->addLog("unattachtimer", array(
8237  "timer" => "all",
8238  "number" => $c
8239  ));
8240  }
8241  return $err;
8242  }
8243  /**
8244  * return all activated document timer
8245  * @return array of doctimer values
8246  */
8247  final public function getAttachedTimers()
8248  {
8249  include_once ("Class.QueryDb.php");
8250  include_once ("Class.DocTimer.php");
8251  $q = new QueryDb($this->dbaccess, "doctimer");
8252  $q->AddQuery("docid=" . $this->initid);
8253  $q->AddQuery("donedate is null");
8254  $l = $q->Query(0, 0, "TABLE");
8255 
8256  if (is_array($l)) return $l;
8257  return array();
8258  }
8259  /**
8260  * get all domains where document is attached by current user
8261  * @param boolean $user is set to false list all domains (independant of current user)
8262  * @param boolean $folderName is set to true append also folder name
8263  * @return array id
8264  */
8265  public function getDomainIds($user = true, $folderName = false)
8266  {
8267  if (file_exists("OFFLINE/Class.DomainManager.php")) {
8268  include_once ("FDL/Class.SearchDoc.php");
8269  $s = new searchDoc($this->dbaccess, "OFFLINEFOLDER");
8270  $s->join("id = fld(dirid)");
8271  $s->addFilter("fld.childid = %d", $this->initid);
8272  $uid = $this->getUserId();
8273  if ($user) $s->addFilter("off_user = '%d' or off_user is null", $uid);
8274  $s->noViewControl();
8275  $t = $s->search();
8276  $ids = array();
8277  foreach ($t as $v) {
8278  $ids[] = $v['off_domain'];
8279  if ($folderName && ((!$user) || ($v['off_user'] == $uid))) {
8280  $ids[] = $v["name"];
8281  }
8282  }
8283  return array_unique($ids);
8284  }
8285  return null;
8286  }
8287  /**
8288  * attach lock to specific domain.
8289  * @param int $domainId domain identificator
8290  * @return string error message
8291  */
8292  public function lockToDomain($domainId, $userid = '')
8293  {
8294  $err = '';
8295  if (!$userid) $userid = $this->userid;
8296 
8297  if ($domainId != '') {
8298  /*
8299  * Memorize current core lock and lock document
8300  */
8301  if ($this->lockdomainid != $domainId) {
8302  /*
8303  * Memorize current core lock if lockdomain changes
8304  */
8305  $this->addUTag(1, 'LOCKTODOMAIN_LOCKED', $this->locked);
8306  }
8307  $err = $this->lock(false, $userid);
8308  if ($err != '') {
8309  return $err;
8310  }
8311  } else {
8312  /*
8313  * Restore core lock
8314  */
8315  $tag = $this->getUTag('LOCKTODOMAIN_LOCKED', true, 1);
8316  if ($tag !== false) {
8317  $this->delUTag(1, 'LOCKTODOMAIN_LOCKED');
8318  $this->locked = $tag->comment;
8319  $err = $this->modify(true, array(
8320  "locked"
8321  ) , true);
8322  if ($err != '') {
8323  return $err;
8324  }
8325  }
8326  }
8327  /*
8328  * Set or remove domain's lock
8329  */
8330  $this->lockdomainid = $domainId;
8331  $err = $this->modify(true, array(
8332  "lockdomainid"
8333  ) , true);
8334  return $err;
8335  }
8336  /**
8337  * return folder where document is set into
8338  * @return array of folder identificators
8339  */
8340  public function getParentFolderIds()
8341  {
8342  $fldids = array();
8343  $err = simpleQuery($this->dbaccess, sprintf("select dirid from fld where qtype='S' and childid=%d", $this->initid) , $fldids, true, false);
8344  return $fldids;
8345  }
8346  /**
8347  * update Domain list
8348  */
8349  public function updateDomains()
8350  {
8351  $domains = $this->getDomainIds(false, true);
8352  //delete domain lock if is not in the list
8353  $this->domainid = trim($this->_array2val($domains));
8354  if ($this->lockdomainid) {
8355  if (!in_array($this->lockdomainid, $domains)) $this->lockdomainid = '';
8356  else {
8357  if ($this->locked > 0) {
8358  $err = simpleQuery($this->dbaccess, sprintf("select login from users where id=%d", $this->locked) , $lockLogin, true, true);
8359 
8360  if ($lockLogin && (!$this->isInDomain(true, $lockLogin))) {
8361  $this->lockdomainid = '';
8362  }
8363  }
8364  }
8365  }
8366 
8367  $this->modify(true, array(
8368  "domainid",
8369  "lockdomainid"
8370  ) , true);
8371  }
8372  /**
8373  * verify is doc is set in a domain
8374  * @param boolean $user limit domains where user as set document
8375  * @param string $login another login else current user
8376  */
8377  public function isInDomain($user = true, $login = '')
8378  {
8379  if ($user) {
8380  global $action;
8381  if (!$login) $login = $action->user->login;
8382  if (preg_match('/_' . $login . '$/m', $this->domainid)) return true;
8383  return false;
8384  } else {
8385  return (!empty($this->domainid));
8386  }
8387  }
8388  /**
8389  * Parse a zone string "FOO:BAR[-1]:B:PDF?k1=v1,k2=v2" into an array:
8390  *
8391  * array(
8392  * 'fulllayout' => 'FOO:BAR[-1]:B:PDF',
8393  * 'args' => 'k1=v1,k2=v2',
8394  * 'argv' => array(
8395  * 'k1' => 'v1',
8396  * 'k2' => 'v2
8397  * ),
8398  * 'app' => 'FOO',
8399  * 'layout' => 'BAR',
8400  * 'index' => '-1',
8401  * 'modifier' => 'B',
8402  * 'transform' => 'PDF'
8403  * )
8404  *
8405  * @param zone string "APP:LAYOUT:etc." $zone
8406  * @return false on error or an array containing the components
8407  */
8408  static public function parseZone($zone)
8409  {
8410  $p = array();
8411  // Separate layout (left) from args (right)
8412  $split = preg_split('/\?/', $zone, 2);
8413  $left = $split[0];
8414  $right = $split[1];
8415  // Check that the layout part has al least 2 elements
8416  $el = preg_split('/:/', $left);
8417  if (count($el) < 2) {
8418  return false;
8419  }
8420  $p['fulllayout'] = $left;
8421  $p['index'] = - 1;
8422  // Parse args into argv (k => v)
8423  if ($right != "") {
8424  $p['args'] = $right;
8425  $argList = preg_split('/&/', $p['args']);
8426  $p['argv'] = array();
8427  foreach ($argList as $arg) {
8428  $split = preg_split('/=/', $arg, 2);
8429  $left = urldecode($split[0]);
8430  $right = urldecode($split[1]);
8431  $p['argv'][$left] = $right;
8432  }
8433  }
8434  // Parse layout
8435  $parts = array(
8436  0 => 'app',
8437  1 => 'layout',
8438  2 => 'modifier',
8439  3 => 'transform'
8440  );
8441  $match = array();
8442  $i = 0;
8443  while ($i < count($el)) {
8444  if (!array_key_exists($i, $parts)) {
8445  error_log(__CLASS__ . "::" . __FUNCTION__ . " " . sprintf("Unexpected part '%s' in zone '%s'.", $el[$i], $zone));
8446  return false;
8447  }
8448  // Extract index from 'layout' part if present
8449  if ($i == 1 && preg_match("/^(?P<name>.*?)\[(?P<index>-?\d)\]$/", $el[$i], $match)) {
8450  $p[$parts[$i]] = $match['name'];
8451  $p['index'] = $match['index'];
8452  $i++;
8453  continue;
8454  }
8455  // Store part
8456  $p[$parts[$i]] = $el[$i];
8457  $i++;
8458  }
8459 
8460  return $p;
8461  }
8462  }
8463 ?>
← centre documentaire © anakeen - published under CC License - Dynacase