Core  3.2
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  * @package FDL
5 */
6 /**
7  * Document Object Definition
8  *
9  * @author Anakeen
10  * @version $Id: Class.Doc.php,v 1.562 2009/01/14 09:18:05 eric Exp $
11  * @package FDL
12  */
13 /**
14  */
15 
16 include_once ("Class.QueryDb.php");
17 include_once ("Lib.FileMime.php");
18 include_once ("FDL/Class.DocCtrl.php");
19 include_once ("FDL/freedom_util.php");
20 include_once ("FDL/Class.DocVaultIndex.php");
21 include_once ("FDL/Class.DocAttr.php");
22 include_once ("FDL/Class.DocHisto.php");
23 include_once ('FDL/Class.ADoc.php');
24 // define constant for search attributes in concordance with the file "init.freedom"
25 /**#@+
26  * constant for document family identifier in concordance with the file "FDL/init.freedom"
27  *
28 */
29 define("FAM_BASE", 1);
30 define("FAM_DIR", 2);
31 define("FAM_ACCESSDOC", 3);
32 define("FAM_ACCESSDIR", 4);
33 define("FAM_SEARCH", 5);
34 define("FAM_ACCESSSEARCH", 6);
35 define("FAM_ACCESSFAM", 23);
36 define("MENU_ACTIVE", 1);
37 define("MENU_INVISIBLE", 2);
38 define("MENU_INACTIVE", 0);
39 
40 define('POPUP_INACTIVE', 0);
41 define('POPUP_ACTIVE', 1);
42 define('POPUP_CTRLACTIVE', 3);
43 define('POPUP_CTRLINACTIVE', 4);
44 define('POPUP_INVISIBLE', 2);
45 
46 define("DELVALUE", 'DEL??');
47 /**#@-*/
48 /**
49  * max cache document
50  */
51 define("MAXGDOCS", 20);
52 
53 define("REGEXPFILE", "([^\|]*)\|([0-9]*)\|?(.*)?");
54 define("PREGEXPFILE", "/(?P<mime>[^\|]*)\|(?P<vid>[0-9]*)\|?(?P<name>.*)?/");
55 /**
56  * Document Class
57  */
58 class Doc extends DocCtrl
59 {
60  const USEMASKCVVIEW = - 1;
61  const USEMASKCVEDIT = - 2;
62  public $fields = array(
63  "id",
64  "owner",
65  "title",
66  "revision",
67  "version",
68  "initid",
69  "fromid",
70  "doctype",
71  "locked",
72  "allocated",
73  "archiveid",
74  "icon",
75  "lmodify",
76  "profid",
77  "usefor",
78  "cdate",
79  "adate",
80  "revdate",
81  "comment",
82  "classname",
83  "state",
84  "wid",
85  "postitid",
86  "domainid",
87  "lockdomainid",
88  "cvid",
89  "name",
90  "dprofid",
91  "views",
92  "atags",
93  "prelid",
94  "confidential",
95  "ldapdn"
96  );
97  /**
98  * @var string searchable values
99  */
100  protected $svalues;
101  public $sup_fields = array(
102  "values",
103  "attrids"
104  ); // not be in fields else trigger error
105  public static $infofields = array(
106  "id" => array(
107  "type" => "integer",
108  "displayable" => true,
109  "sortable" => true,
110  "filterable" => true,
111  "label" => "prop_id"
112  ) , # N_("prop_id")
113  "owner" => array(
114  "type" => "uid",
115  "displayable" => true,
116  "sortable" => true,
117  "filterable" => true,
118  "label" => "prop_owner"
119  ) , # N_("prop_owner"),
120  "icon" => array(
121  "type" => "image",
122  "displayable" => true,
123  "sortable" => false,
124  "filterable" => false,
125  "label" => "prop_icon"
126  ) , # N_("prop_icon"),
127  "title" => array(
128  "type" => "text",
129  "displayable" => true,
130  "sortable" => true,
131  "filterable" => true,
132  "label" => "prop_title"
133  ) , # N_("prop_title"),
134  "revision" => array(
135  "type" => "integer",
136  "displayable" => true,
137  "sortable" => true,
138  "filterable" => true,
139  "label" => "prop_revision"
140  ) , # N_("prop_revision"),
141  "version" => array(
142  "type" => "text",
143  "displayable" => true,
144  "sortable" => true,
145  "filterable" => true,
146  "label" => "prop_version"
147  ) , # N_("prop_version"),
148  "initid" => array(
149  "type" => "docid",
150  "displayable" => true,
151  "sortable" => true,
152  "filterable" => true,
153  "label" => "prop_initid"
154  ) , # N_("prop_initid"),
155  "fromid" => array(
156  "type" => "docid",
157  "displayable" => true,
158  "sortable" => true,
159  "filterable" => true,
160  "label" => "prop_fromid"
161  ) , # N_("prop_fromid"),
162  "doctype" => array(
163  "type" => "text",
164  "displayable" => false,
165  "sortable" => true,
166  "filterable" => true,
167  "label" => "prop_doctype"
168  ) , # N_("prop_doctype"),
169  "locked" => array(
170  "type" => "uid",
171  "displayable" => true,
172  "sortable" => false,
173  "filterable" => false,
174  "label" => "prop_locked"
175  ) , # N_("prop_locked"),
176  "allocated" => array(
177  "type" => "uid",
178  "displayable" => false,
179  "sortable" => true,
180  "filterable" => true,
181  "label" => "prop_allocated"
182  ) , # N_("prop_allocated"),
183  "lmodify" => array(
184  "type" => "text",
185  "displayable" => false,
186  "sortable" => false,
187  "filterable" => false,
188  "label" => "prop_lmodify"
189  ) , # N_("prop_lmodify"),
190  "profid" => array(
191  "type" => "integer",
192  "displayable" => false,
193  "sortable" => false,
194  "filterable" => false,
195  "label" => "prop_profid"
196  ) , # N_("prop_profid"),
197  "usefor" => array(
198  "type" => "text",
199  "displayable" => false,
200  "sortable" => false,
201  "filterable" => false,
202  "label" => "prop_usefor"
203  ) , # N_("prop_usefor")
204  "cdate" => array(
205  "type" => "timestamp",
206  "displayable" => true,
207  "sortable" => true,
208  "filterable" => true,
209  "label" => "prop_cdate"
210  ) , # N_("prop_cdate")
211  "adate" => array(
212  "type" => "timestamp",
213  "displayable" => true,
214  "sortable" => true,
215  "filterable" => true,
216  "label" => "prop_adate"
217  ) , # N_("prop_adate"),
218  "revdate" => array(
219  "type" => "timestamp",
220  "displayable" => true,
221  "sortable" => true,
222  "filterable" => true,
223  "label" => "prop_revdate"
224  ) , # N_("prop_revdate"),
225  "comment" => array(
226  "type" => "text",
227  "displayable" => false,
228  "sortable" => false,
229  "filterable" => false,
230  "label" => "prop_comment"
231  ) , # N_("prop_comment"),
232  "classname" => array(
233  "type" => "text",
234  "displayable" => false,
235  "sortable" => false,
236  "filterable" => false,
237  "label" => "prop_classname"
238  ) , # N_("prop_classname")
239  "state" => array(
240  "type" => "text",
241  "displayable" => true,
242  "sortable" => true,
243  "filterable" => true,
244  "label" => "prop_state"
245  ) , # N_("prop_state"),
246  "wid" => array(
247  "type" => "docid",
248  "displayable" => false,
249  "sortable" => false,
250  "filterable" => false,
251  "label" => "prop_wid"
252  ) , # N_("prop_wid")
253  "postitid" => array(
254  "type" => "text",
255  "displayable" => false,
256  "sortable" => false,
257  "filterable" => false,
258  "label" => "prop_postitid"
259  ) , # N_("prop_postitid")
260  "cvid" => array(
261  "type" => "integer",
262  "displayable" => false,
263  "sortable" => false,
264  "filterable" => false,
265  "label" => "prop_cvid"
266  ) , # N_("prop_cvid")
267  "name" => array(
268  "type" => "text",
269  "displayable" => true,
270  "sortable" => true,
271  "filterable" => true,
272  "label" => "prop_name"
273  ) , # N_("prop_name")
274  "dprofid" => array(
275  "type" => "docid",
276  "displayable" => false,
277  "sortable" => false,
278  "filterable" => false,
279  "label" => "prop_dprofid"
280  ) , # N_("prop_dprofid")
281  "atags" => array(
282  "type" => "text",
283  "displayable" => false,
284  "sortable" => false,
285  "filterable" => false,
286  "label" => "prop_atags"
287  ) , # N_("prop_atags")
288  "prelid" => array(
289  "type" => "docid",
290  "displayable" => false,
291  "sortable" => false,
292  "filterable" => false,
293  "label" => "prop_prelid"
294  ) , # N_("prop_prelid")
295  "lockdomainid" => array(
296  "type" => "docid",
297  "displayable" => true,
298  "sortable" => true,
299  "filterable" => false,
300  "label" => "prop_lockdomainid"
301  ) , # N_("prop_lockdomainid")
302  "domainid" => array(
303  "type" => "docid",
304  "displayable" => false,
305  "sortable" => false,
306  "filterable" => false,
307  "label" => "prop_domainid"
308  ) , # N_("prop_domainid")
309  "confidential" => array(
310  "type" => "integer",
311  "displayable" => false,
312  "sortable" => false,
313  "filterable" => true,
314  "label" => "prop_confidential"
315  ) , # N_("prop_confidential")
316  "svalues" => array(
317  "type" => "fulltext",
318  "displayable" => false,
319  "sortable" => false,
320  "filterable" => true,
321  "label" => "prop_svalues"
322  ) , # N_("prop_svalues")
323  "ldapdn" => array(
324  "type" => "text",
325  "displayable" => false,
326  "sortable" => false,
327  "filterable" => false,
328  "label" => "prop_ldapdn"
329  )
330  ); # N_("prop_ldapdn");
331 
332  /**
333  * identifier of the document
334  * @var int
335  */
336  public $id;
337  /**
338  * user identifier for the creator
339  * @var int
340  */
341  public $owner;
342  /**
343  * the title of the document
344  * @var string
345  */
346  public $title;
347  /**
348  * number of the revision. First is zero
349  * @var int
350  */
351  public $revision;
352  /**
353  * tag for version
354  * @var string
355  */
356  public $version;
357  /**
358  * identifier of the first revision document
359  * @var int
360  */
361  public $initid;
362  /**
363  * identifier of the family document
364  * @var int
365  */
366  public $fromid;
367  /**
368  * domain where document is lock
369  * @var int
370  */
372  /**
373  * domain where document is attached
374  * @var array
375  */
376  public $domainid;
377  /**
378  * the type of document
379  *
380  * F : normal document (default)
381  * C : family document
382  * D : folder document
383  * P : profil document
384  * S : search document
385  * T : temporary document
386  * W : workflow document
387  * Z : zombie document
388  *
389  * @var string single character
390  */
391  public $doctype;
392  /**
393  * user identifier for the locker
394  * @vart
395  */
396  public $locked;
397  /**
398  * filename or vault id for the icon
399  * @var string
400  */
401  public $icon;
402  /**
403  * set to 'Y' if the document has been modify until last revision
404  * @var string single character
405  */
406  public $lmodify;
407  /**
408  * identifier of the profil document
409  * @var int
410  */
411  public $profid;
412  /**
413  * user/group/role which can view document
414  * @var string
415  */
416  public $views;
417  /**
418  * to precise a special use of the document
419  * @var string single character
420  */
421  public $usefor;
422  /**
423  * date of the last modification (the revision date for fixed document)
424  * @var int
425  */
426  public $revdate;
427  /**
428  * date of creation
429  * @var string date 'YYYY-MM-DD'
430  */
431  public $cdate;
432  /**
433  * date of latest access
434  * @var string date 'YYYY-MM-DD'
435  */
436  public $adate;
437  /**
438  * @deprecated old history notation
439  * @var string
440  */
441  public $comment;
442  /**
443  * class name in case of special family (only set in family document)
444  * @var string
445  */
446  public $classname;
447  /**
448  * state of the document if it is associated with a workflow
449  * @var string
450  */
451  public $state;
452  /**
453  * identifier of the workflow document
454  *
455  * if 0 then no workflow
456  * @var int
457  */
458  public $wid;
459  /**
460  * identifier of the control view document
461  *
462  * if 0 then no special control view
463  * @var int
464  */
465  public $cvid;
466  /**
467  * string identifier of the document
468  *
469  * @var string
470  */
471  public $name;
472  /**
473  * identifier of the mask document
474  *
475  * if 0 then no mask
476  * @var int
477  */
478  public $mid = 0;
479  /**
480  * identifier of dynamic profil
481  *
482  * if 0 then no dynamic profil
483  * @var int
484  */
485  public $dprofid = 0;
486  /**
487  * primary relation id
488  *
489  * generally towards a folder
490  * @var int
491  */
492  public $prelid = 0;
493  /**
494  * applications tag
495  * use by specifics applications to search documents by these tags
496  *
497  * @var string
498  */
499  public $atags;
500  /**
501  * idengtificator of document's note
502  * @var int
503  */
504  public $postitid;
505  /**
506  * confidential level
507  * if not 0 this document is confidential, only user with the permission 'confidential' can read this
508  *
509  * @var int
510  */
512  /**
513  * Distinguish Name for LDAP use
514  *
515  * @var string
516  */
517  public $ldapdn;
518  /**
519  * Allocate user id
520  *
521  * @var int
522  */
523  public $allocated;
524  /**
525  * Archive document id
526  *
527  * @var int
528  */
529  public $archiveid;
530  /**
531  * @var string logical name family
532  */
533  public $fromname;
534  /**
535  * @var string raw family title
536  */
537  public $fromtitle;
538  /**
539  * @var string fulltext vector
540  */
541  public $fulltext;
542  /**
543  * for system purpose only
544  * @var string concatenation of all values
545  */
546  protected $values;
547  /**
548  * for system purpose only
549  * @var string concatenation of all attribute ids (use it with ::values)
550  */
551  protected $attrids;
552  /**
553  * param value cache
554  * @var array
555  */
556  private $_paramValue = array();
557  /**
558  * @var string last modify error when refresh
559  */
560  private $lastRefreshError = '';
561  private $formaterLevel = 0;
562  private $otherFormatter = array();
563  /**
564  * identification of special views
565  *
566  * @var array
567  */
568  public $cviews = array(
569  "FDL:VIEWBODYCARD",
570  "FDL:VIEWABSTRACTCARD",
571  "FDL:VIEWTHUMBCARD"
572  );
573  public $eviews = array(
574  "FDL:EDITBODYCARD"
575  );
576  /**
577  * @var WDoc
578  */
579  public $wdoc = null;
580  /**
581  * @var Adoc
582  */
583  public $attributes = null;
584  public static $sqlindex = array(
585  "doc_initid" => array(
586  "unique" => false,
587  "on" => "initid"
588  ) ,
589  "doc_title" => array(
590  "unique" => false,
591  "on" => "title"
592  ) ,
593  "doc_name" => array(
594  "unique" => true,
595  "on" => "name,revision,doctype"
596  ) ,
597  "doc_full" => array(
598  "unique" => false,
599  "using" => "@FDL_FULLIDX",
600  "on" => "fulltext"
601  ) ,
602  "doc_profid" => array(
603  "unique" => false,
604  "on" => "profid"
605  )
606  );
607  public $id_fields = array(
608  "id"
609  );
610 
611  public $dbtable = "doc";
612 
613  public $order_by = "title, revision desc";
614 
615  public $fulltextfields = array(
616  "title"
617  );
618  private $mvalues = array();
619  /**
620  * number of disabledEditControl
621  */
622  private $withoutControlN = 0;
623  private $withoutControl = false;
624  private $constraintbroken = false; // true if one constraint is not verified
625  private $_oldvalue = array();
626  private $fathers = null;
627  private $childs = null;
628  /**
629  * @var DocHtmlFormat
630  */
631  private $htmlFormater = null;
632  /**
633  * @var DocOooFormat
634  */
635  private $oooFormater = null;
636  /**
637  * used by fulltext indexing
638  * @var array
639  */
640  private $textsend = array();
641  private $vidNoSendTextToEngine = array();
642  /**
643  * to not detect changed when it is automatic setValue
644  * @var bool
645  */
646  private $_setValueCompleteArray = false;
647  /**
648  * list of availaible control
649  * @var array
650  */
651  public $acls = array();
652  /**
653  * document layout
654  * @var Layout|OooLayout
655  */
656  public $lay = null;
657  /**
658  * default family id for the profil access
659  * @var int
660  */
662  public $sqlcreate = "
663 create table doc ( id int not null,
664  primary key (id),
665  owner int,
666  title varchar(256),
667  revision int DEFAULT 0,
668  initid int,
669  fromid int,
670  doctype char DEFAULT 'F',
671  locked int DEFAULT 0,
672  archiveid int DEFAULT 0,
673  allocated int DEFAULT 0,
674  icon text,
675  lmodify char DEFAULT 'N',
676  profid int DEFAULT 0,
677  usefor text DEFAULT 'N',
678  revdate int,
679  version text,
680  cdate timestamp,
681  adate timestamp,
682  comment text,
683  classname text,
684  state text,
685  wid int DEFAULT 0,
686  values text DEFAULT '',
687  attrids text DEFAULT '',
688  fulltext tsvector,
689  postitid text,
690  domainid text,
691  lockdomainid int,
692  cvid int,
693  name text,
694  dprofid int DEFAULT 0,
695  views int[],
696  prelid int DEFAULT 0,
697  atags text,
698  confidential int DEFAULT 0,
699  ldapdn text,
700  svalues text DEFAULT ''
701  );
702 create table docfrom ( id int not null,
703  primary key (id),
704  fromid int);
705 create table docname ( name text not null,
706  primary key (name),
707  id int,
708  fromid int);
709 create sequence seq_id_doc start 1000;
710 create sequence seq_id_tdoc start 1000000000;
711 create index i_docname on doc(name);
712 create unique index i_docir on doc(initid, revision);";
713  // --------------------------------------------------------------------
714  //---------------------- OBJECT CONTROL PERMISSION --------------------
715  public $obj_acl = array(); // set by childs classes
716  // --------------------------------------------------------------------
717 
718  /**
719  * default view to view card
720  * @var string
721  */
722  public $defaultview = "FDL:VIEWBODYCARD";
723  /**
724  * default view to edit card
725  * @var string
726  */
727  public $defaultedit = "FDL:EDITBODYCARD";
728  /**
729  * default view for abstract card
730  * @var string
731  */
732  public $defaultabstract = "FDL:VIEWABSTRACTCARD";
733  /**
734  * default view use when edit document for the first time (creation mode)
735  * @var string
736  */
737  public $defaultcreate = "";
738  /**
739  * for email : the same as $defaultview by default
740  * @var string
741  */
742  public $defaultmview = "";
743  /**
744  * use when family wants to define a special context menu
745  * @var array
746  */
747  public $specialmenu = array();
748 
749  public $defDoctype = 'F';
750  /**
751  * to indicate values modification
752  * @var bool
753  * @access private
754  */
755  private $hasChanged = false;
756 
757  public $paramRefresh = array();
758  /**
759  * optimize: compute mask in needed only
760  * @var bool
761  * @access private
762  */
763  private $_maskApplied = false; // optimize: compute mask if needed only
764 
765  /**
766  * By default, setValue() will call completeArrayRow when setting
767  * values of arrays columns.
768  * @var bool
769  * @access private
770  */
771  private $_setValueNeedCompleteArray = true;
772  /**
773  * display document main properties as string
774  * @return string
775  */
776  public function __toString()
777  {
778  return sprintf('%s "%s" [#%d]', $this->fromname, $this->getTitle() , $this->id);
779  }
780  /**
781  * Increment sequence of family and call to Doc::PostCreated
782  * send mail if workflow is attached to it
783  * affect profil
784  * @see Doc::PostCreated
785  *
786  * @return void
787  */
788  final public function postInsert()
789  {
790  // controlled will be set explicitly
791  //$this->SetControl();
792  if (($this->revision == 0) && ($this->doctype != "T")) {
793  // increment family sequence
794  $this->nextSequence();
795  $famDoc = $this->getFamilyDocument();
796  $incumbentName = getCurrentUser()->getIncumbentPrivilege($famDoc, 'create');
797  $createComment = _("document creation");
798  if ($incumbentName) $createComment = sprintf(_("(substitute of %s) : ") , $incumbentName) . $createComment;
799  $this->addHistoryEntry($createComment, HISTO_INFO, "CREATE");
800  if ($this->wdoc) {
801  $this->wdoc->workflowSendMailTemplate($this->state, _("creation"));
802  $this->wdoc->workflowAttachTimer($this->state);
803  $this->wdoc->changeAllocateUser($this->state);
804  }
805  $this->addLog("create", array(
806  "id" => $this->id,
807  "title" => $this->title,
808  "fromid" => $this->fromid,
809  "fromname" => $this->fromname
810  ));
811  }
812  unset($this->fields["svalues"]);
813  $this->Select($this->id);
814  // set creation date
815  $this->cdate = $this->getTimeDate(0, true);
816  $this->adate = $this->cdate;
817  $date = gettimeofday();
818  $this->revdate = $date['sec'];
819  $this->modify(true, array(
820  "cdate",
821  "adate",
822  "revdate"
823  ) , true); // to force also execute sql trigger
824  if ($this->doctype != 'C') {
825  // set to shared : because comes from createDoc
826  \Dcp\Core\SharedDocuments::set($this->id, $this);
827  }
828  if ($this->doctype != "T") {
829  $err = $this->PostCreated();
830  if ($err != "") AddWarningMsg($err);
831  $this->sendTextToEngine();
832  if ($this->dprofid > 0) {
833  $this->setProfil($this->dprofid); // recompute profil if needed
834  $this->modify(true, array(
835  "profid"
836  ) , true);
837  }
838  $this->UpdateVaultIndex();
839  $this->updateRelations(true);
840  }
841  $this->hasChanged = false;
842  }
843 
844  function setChanged()
845  {
846  $this->hasChanged = true;
847  }
848  /**
849  * return true if document has changed after setValue/clearValue calling
850  * @api test if document attributes are changed
851  * @return bool
852  */
853  function isChanged()
854  {
855  return ($this->hasChanged === true);
856  }
857  /**
858  * set default values and creation date
859  * the access control is provided by {@see Doc::createDoc()} function.
860  * call {@see Doc::PreCreated()} method before execution
861  *
862  * @return string error message, if no error empty string
863  */
864  final public function PreInsert()
865  {
866 
867  $err = $this->PreCreated();
868  if ($err != "") return $err;
869  // compute new id
870  if ($this->id == "") {
871  if ($this->doctype == 'T') $res = pg_query($this->init_dbid() , "select nextval ('seq_id_tdoc')");
872  else $res = pg_query($this->init_dbid() , "select nextval ('seq_id_doc')");
873  $arr = pg_fetch_array($res, 0);
874  $this->id = $arr[0];
875  }
876  // set default values
877  if ($this->initid == "") $this->initid = $this->id;
878  $this->RefreshTitle();
879  if (chop($this->title) == "") {
880  $fdoc = $this->getFamilyDocument();
881  $this->title = sprintf(_("untitle %s %d") , $fdoc->title, $this->initid);
882  }
883  if ($this->doctype == "") $this->doctype = $this->defDoctype;
884  if ($this->revision == "") $this->revision = "0";
885 
886  if ($this->profid == "") {
887  $this->views = "{0}";
888  $this->profid = "0";
889  }
890  if ($this->usefor == "") $this->usefor = "N";
891 
892  if ($this->lmodify == "") $this->lmodify = "N";
893  if ($this->locked == "") $this->locked = "0";
894  if ($this->owner == "") $this->owner = $this->userid;
895  // if ($this->state == "") $this->state=$this->firstState;
896  $this->version = $this->getVersion();
897 
898  if ($this->name && $this->revision == 0) {
899  $err = $this->setLogicalName($this->name, false, true);
900  if ($err) {
901  return $err;
902  }
903  }
904  unset($this->fields["svalues"]);
905  if ($this->doctype !== "T") {
906  $this->svalues = $this->getExtraSearchableDisplayValues();
907  $this->fields["svalues"] = "svalues";
908  }
909  if ($this->wid > 0) {
910  /*
911  * @var WDoc $wdoc
912  */
913  $wdoc = new_Doc($this->dbaccess, $this->wid);
914  $this->wdoc = $wdoc;
915  if ($this->wdoc->isAlive()) {
916  if ($this->wdoc->doctype != 'W') $err = sprintf(_("creation : document %s is not a workflow") , $this->wid);
917  else $this->wdoc->Set($this); // set first state
918 
919  } else $err = sprintf(_("creation : workflow %s not exists") , $this->wid);
920  } else {
921  $this->wdoc = null;
922  }
923  return $err;
924  }
925  /**
926  * Verify control edit
927  *
928  * if {@link Doc::disableEditControl()} is call before control permission is desactivated
929  * if attribute values are changed the modification date is updated
930  * @return string error message, if no error empty string
931  */
932  function preUpdate()
933  {
934  if ($this->id == "") return _("cannot update no initialized document");
935  if ($this->doctype == 'I') return _("cannot update inconsistent document"); // provides from waiting document or searchDOc with setReturns
936  if (!$this->withoutControl) {
937  $err = $this->control("edit");
938  if ($err != "") return ($err);
939  }
940  if ($this->locked == - 1) $this->lmodify = 'N';
941  $err = $this->docIsCleanToModify();
942  if ($err) return $err;
943  if ($this->constraintbroken) return (sprintf(_("constraint broken %s") , $this->constraintbroken));
944 
945  unset($this->fields["svalues"]);
946  $this->RefreshTitle();
947  if ($this->hasChanged) {
948  if (chop($this->title) == "") $this->title = _("untitle document");
949  // set modification date
950  if ($this->doctype !== "T") {
951  $this->svalues = $this->getExtraSearchableDisplayValues();
952  $this->fields["svalues"] = "svalues";
953  }
954  $date = gettimeofday();
955  $this->revdate = $date['sec'];
956  $this->version = $this->getVersion();
957  $this->lmodify = 'Y';
958  }
959 
960  return '';
961  }
962 
963  private function docIsCleanToModify()
964  {
965  if ($this->initid > 0 && $this->fromid > 0) {
966  simpleQuery($this->dbaccess, sprintf("select initid, id, revision, locked from only doc%d where initid=%d", $this->fromid, $this->initid) , $r);
967 
968  $cAlive = 0;
969  $imAlive = false;
970  foreach ($r as $docInfo) {
971  if (($docInfo["id"] == $this->id) && ($docInfo["locked"] == - 1)) {
972  return ErrorCode::getError('DOC0118', $this->getTitle() , $this->id);
973  } elseif ($docInfo["locked"] != - 1) {
974  if ($docInfo["id"] == $this->id) $imAlive = true;
975  $cAlive++;
976  }
977  }
978  if ($this->locked != - 1 && $cAlive == 1 && $imAlive) {
979  return ''; // OK
980 
981  } elseif ($cAlive > 1) {
982  // multiple alive already set : need fix it
984  if ($this->isFixed()) { // if locked now ?
985  return ErrorCode::getError('DOC0119', $this->getTitle() , $this->id);
986  }
987  }
988  }
989  return '';
990  }
991  /**
992  * optimize for speed : memorize object for future use
993  * @return string
994  */
995  function postUpdate()
996  {
998 
999  if ($this->hasChanged) {
1000  $this->computeDProfil();
1001  if ($this->doctype != 'C') {
1002  $this->regenerateTemplates();
1003  $this->UpdateVaultIndex();
1004  $this->updateRelations();
1005 
1006  if ($this->getATag("DYNTIMER")) $this->resetDynamicTimers();
1007  $this->addLog("changed", array_keys($this->getOldRawValues()));
1008  }
1009  }
1010  $this->sendTextToEngine();
1011  $this->hasChanged = false;
1012  return '';
1013  }
1014  /**
1015  * Regenerate the template referenced by an attribute
1016  *
1017  * @param string $aid the name of the attribute holding the template
1018  * @param int $index the value for $index row (default value -1 means all values)
1019  * @return string error message, if no error empty string
1020  */
1021  function regenerateTemplate($aid, $index = - 1)
1022  {
1023  $layout = 'THIS:' . $aid;
1024  if ($index > - 1) {
1025  $layout.= '[' . $index . ']';
1026  }
1027  $orifile = $this->getZoneFile($layout);
1028  if (!$orifile) {
1029  $err = sprintf(_("Dynamic template %s not found ") , $orifile);
1030  return $err;
1031  }
1032  if (!file_exists($orifile)) {
1033  $err = sprintf(_("Dynamic template %s not found ") , $orifile);
1035  return $err;
1036  }
1037  if (getFileExtension($orifile) != 'odt') {
1038  $err = sprintf(_("Dynamic template %s not an odt file ") , $orifile);
1040  return $err;
1041  }
1042  $outfile = $this->viewDoc($layout . ':B', 'ooo');
1043  if (!file_exists($outfile)) {
1044  $err = sprintf(_("viewDoc did not returned a valid file"));
1046  return $err;
1047  }
1048  $fh = fopen($outfile, 'rb');
1049  if ($fh === false) {
1050  $err = sprintf(_("Error opening %s file '%s'") , 'outfile', $outfile);
1052  return $err;
1053  }
1054  $err = $this->saveFile($aid, $fh, '', $index);
1055  if ($err != '') {
1057  return $err;
1058  }
1059  fclose($fh);
1060  $this->addHistoryEntry(sprintf(_('regeneration of file template %s') , $aid));
1061  return '';
1062  }
1063  /**
1064  * Regenerate all templates referenced by the document attributes
1065  *
1066  * @return string error message, if no error empty string
1067  */
1068  final function regenerateTemplates()
1069  {
1070  $fa = $this->GetFileAttributes();
1071  $errorList = array();
1072  foreach ($fa as $aid => $oattr) {
1073  $opt = $oattr->getOption("template");
1074  if ($opt == "dynamic" || $opt == "form") {
1075  if ($oattr->inArray()) {
1076  $ta = $this->getMultipleRawValues($aid);
1077  foreach ($ta as $k => $v) {
1078  $err = $this->regenerateTemplate($aid, $k);
1079  if ($err != '') {
1080  array_push($errorList, $err);
1081  }
1082  }
1083  } else {
1084  $err = $this->regenerateTemplate($aid);
1085  if ($err != '') {
1086  array_push($errorList, $err);
1087  }
1088  }
1089  }
1090  }
1091  if (count($errorList) > 0) {
1092  return join("\n", $errorList);
1093  }
1094  return '';
1095  }
1096  /**
1097  * Set relation doc id use on docrel table
1098  * @param bool $force true to reinit all relations
1099  */
1100  function updateRelations($force = false)
1101  {
1102  // return; // for the moment
1103  include_once ("FDL/Class.DocRel.php");
1104  $or = new DocRel($this->dbaccess);
1105  // $or->resetRelations('',$this->initid); // not necessary now
1106  $or->initRelations($this, $force);
1107  }
1108  /**
1109  * get current sequence number :: number of doc for this family
1110  * @return int
1111  */
1112  function getCurSequence()
1113  {
1114  if ($this->doctype == 'C') return 0;
1115  if ($this->fromid == "") return 0;
1116  // cannot use currval if nextval is not use before
1117  $res = pg_query($this->init_dbid() , "select nextval ('seq_doc" . $this->fromid . "')");
1118  $arr = pg_fetch_array($res, 0);
1119  $cur = intval($arr[0]) - 1;
1120  pg_query($this->init_dbid() , "select setval ('seq_doc" . $this->fromid . "',$cur)");
1121 
1122  return $cur;
1123  }
1124  /**
1125  * set next sequence family
1126  * @param int $fromid
1127  * @return int
1128  */
1129  function nextSequence($fromid = 0)
1130  {
1131  if ($fromid == 0) $fromid = $this->fromid;
1132  if ($this->fromid == 0) return 0;
1133  if ($this->doctype == 'C') return 0;
1134  // cannot use currval if nextval is not use before
1135  $res = pg_query($this->init_dbid() , "select nextval ('seq_doc" . $fromid . "')");
1136  $arr = pg_fetch_array($res, 0);
1137  $cur = intval($arr[0]);
1138  return $cur;
1139  }
1140  /**
1141  * disable edit control for setValue/modify/store
1142  * the document can be modified without testing edit acl
1143  * @see Doc::enableEditControl
1144  * @api disable edit control for setValue/modify/store
1145  */
1146  final public function disableEditControl()
1147  {
1148  $this->withoutControlN++;
1149  $this->withoutControl = true;
1150  }
1151  /**
1152  * default edit control enable
1153  * restore control which are disabled by disableEditControl
1154  * @see Doc::disableEditControl
1155  * @api default edit control enable
1156  */
1157  final public function enableEditControl()
1158  {
1159  $this->withoutControlN--;
1160  if ($this->withoutControlN <= 0) {
1161  $this->withoutControlN = 0;
1162  $this->withoutControl = false;
1163  }
1164  }
1165  /**
1166  * to know if the document can be revised
1167  * @return bool true is revisable
1168  */
1169  public function isRevisable()
1170  {
1171  if (($this->doctype == 'F') && ($this->usefor != 'P')) {
1172  $fdoc = $this->getFamilyDocument();
1173  if ($fdoc->schar != "S") return true;
1174  }
1175  return false;
1176  }
1177  /**
1178  * copy values from anothers document (must be same family or descendant)
1179  *
1180  * @param Doc &$from document source for the transfert
1181  * @return string error message from setValue, if no error, empty string
1182  */
1183  final public function transfertValuesFrom(&$from)
1184  {
1185 
1186  $values = $from->getValues();
1187  $err = "";
1188  foreach ($values as $k => $v) {
1189  $err.= ($err ? '\n' : '') . $this->setValue($k, $v);
1190  }
1191  return $err;
1192  }
1193  /**
1194  * convert to another family
1195  * loose all revisions
1196  * @param int $fromid family identifier where the document will be converted
1197  * @param array $prevalues values which will be added before conversion
1198  * @return doc|false|string the document converted (don't reuse $this) if error return string message
1199  */
1200  final public function convert($fromid, $prevalues = array())
1201  {
1202 
1203  $cdoc = createDoc($this->dbaccess, $fromid);
1204  if (!$cdoc) return false;
1205  if ($this->fromid == $cdoc->fromid) return false; // no convert if not needed
1206  if ($this->locked == - 1) return false; // not revised document
1207  if ($cdoc->fromid == 0) return false;
1208  $f1doc = $this->getFamilyDocument();
1209  $f1from = $f1doc->title . "[" . $f1doc->id . "]";
1210  $f2doc = $cdoc->getFamilyDocument();
1211  $f2from = $f2doc->title . "[" . $f2doc->id . "]";
1212 
1213  $cdoc->id = $this->id;
1214  $cdoc->initid = $this->id;
1215  $cdoc->revision = 0;
1216  $cdoc->cdate = $this->cdate;
1217  $cdoc->revdate = $this->revdate;
1218  $cdoc->adate = $this->adate;
1219  $cdoc->locked = $this->locked;
1220  $cdoc->profid = $this->profid;
1221  $cdoc->dprofid = $this->dprofid;
1222  $cdoc->prelid = $this->prelid;
1223 
1224  $values = $this->getValues();
1225  $point = "dcp:convert" . $this->id;
1226  $this->savePoint($point); // begin transaction in case of fail add
1227  $err = $this->delete(true, false, true); // delete before add to avoid double id (it is not authorized)
1228  if ($err != "") return $err;
1229 
1230  foreach ($prevalues as $k => $v) {
1231  $cdoc->setValue($k, $v);
1232  }
1233  $err = $cdoc->Add(true, true);
1234  if ($err != "") {
1235  $this->rollbackPoint($point);
1236  return $err;
1237  }
1238 
1239  foreach ($values as $k => $v) {
1240  $cdoc->setValue($k, $v);
1241  }
1242 
1243  $err = $cdoc->Modify();
1244  if ($err == "") {
1245  if ($this->revision > 0) {
1246  $this->exec_query(sprintf("update fld set childid=%d where childid=%d", $cdoc->id, $this->initid));
1247  }
1248  }
1249  $this->exec_query(sprintf("update fld set fromid=%d where childid=%d", $cdoc->fromid, $this->initid));
1250 
1251  $cdoc->addHistoryEntry(sprintf(_("convertion from %s to %s family") , $f1from, $f2from));
1252 
1253  $this->commitPoint($point);
1254  if (\Dcp\Core\SharedDocuments::exists($this->id)) {
1255  \Dcp\Core\SharedDocuments::set($this->id, $cdoc);
1256  }
1257 
1258  return $cdoc;
1259  }
1260  /**
1261  * test if the document can be revised now
1262  * it must be locked by the current user
1263  * @deprecated use canEdit instead
1264  * @return string empty means user can update else message of the raison
1265  */
1266  final public function canUpdateDoc()
1267  {
1269  return $this->canEdit();
1270  }
1271  /**
1272  * save document if attribute are change
1273  * not be use when modify properties
1274  * only use with use of setValue.
1275  * @param stdClass $info refresh and postStore messages
1276  * @param boolean $skipConstraint set to true to not test constraints
1277  * @deprecated use ::store() instead
1278  * @return string error message
1279  */
1280  public function save(&$info = null, $skipConstraint = false)
1281  {
1283  $err = '';
1284  $info = new stdClass();
1285  $info->constraint = '';
1286  if (!$skipConstraint) {
1287  $err = $this->verifyAllConstraints(false, $info->constraint);
1288  }
1289  if ($err == '') {
1290  $info->refresh = $this->refresh();
1291  $info->postModify = $this->postStore();
1292  if ($this->hasChanged) {
1293  //in case of change in postModify
1294  $err = $this->modify();
1295  }
1296  if ($err == "") $this->addHistoryEntry(_("save document") , HISTO_INFO, "MODIFY");
1297  }
1298  $info->error = $err;
1299  return $err;
1300  }
1301  /**
1302  * record new document or update
1303  * @api record new document or update it in database
1304  * @param storeInfo $info refresh and postStore messages
1305  * @param boolean $skipConstraint set to true to not test constraints
1306  * @return string error message
1307  */
1308  public function store(&$info = null, $skipConstraint = false)
1309  {
1310  $constraint = [];
1311  $info = new storeInfo();
1312 
1313  $err = $this->preStore();
1314  if ($err) {
1315  $info->preStore = $err;
1316  $info->error = $err;
1317  $info->errorCode = storeInfo::PRESTORE_ERROR;
1318  return $err;
1319  }
1320  if (!$skipConstraint) {
1321  $err = $this->verifyAllConstraints(false, $constraint);
1322  }
1323  if ($err == '') {
1324  $create = false;
1325  if (!$this->isAffected()) {
1326  $err = $this->add();
1327  $create = true;
1328  }
1329  if ($err == '') {
1330  $this->lastRefreshError = '';
1331  $info->refresh = $this->refresh();
1332  $err = $this->lastRefreshError;
1333  if ($err) {
1334  $info->errorCode = storeInfo::UPDATE_ERROR;
1335  } else {
1336  $info->postStore = $this->postStore();
1337  /* @noinspection PhpDeprecationInspection
1338  * compatibility until postModify exists
1339  */
1340  $info->postModify = $info->postStore;
1341  if ($this->hasChanged) {
1342  //in case of change in postStore
1343  $err = $this->modify();
1344  if ($err) $info->errorCode = storeInfo::UPDATE_ERROR;
1345  }
1346  if ($err == "" && (!$create)) $this->addHistoryEntry(_("save document") , HISTO_INFO, "MODIFY");
1347  }
1348  } else {
1349  $info->errorCode = storeInfo::CREATE_ERROR;
1350  }
1351  } else {
1352  $info->errorCode = storeInfo::CONSTRAINT_ERROR;
1353  }
1354  $info->constraint = $constraint;
1355  $info->error = $err;
1356  return $err;
1357  }
1358  /**
1359  * test if the document can be modified by the current user
1360  * the document is not need to be locked
1361  * @param bool $verifyDomain
1362  * @return string empty means user can update else message of the raison
1363  */
1364  public function canEdit($verifyDomain = true)
1365  {
1366  if ($this->locked == - 1) {
1367  $err = sprintf(_("cannot update file %s (rev %d) : fixed. Get the latest version") , $this->title, $this->revision);
1368  return ($err);
1369  }
1370  if ($this->userid == 1) {
1371  return "";
1372  } // admin can do anything but not modify fixed doc
1373  if ($verifyDomain && ($this->lockdomainid > 0)) {
1374  $err = sprintf(_("document is booked in domain %s") , $this->getTitle($this->lockdomainid));
1375  } else {
1376  if ($this->withoutControl) {
1377  return "";
1378  } // no more test if disableEditControl activated
1379  if (($this->locked != 0) && (abs($this->locked) != $this->userid)) {
1380  $user = new Account("", abs($this->locked));
1381  if ($this->locked < - 1) $err = sprintf(_("Document %s is in edition by %s.") , $this->getTitle() , $user->firstname . " " . $user->lastname);
1382  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);
1383  } else {
1384  $err = $this->Control("edit");
1385  }
1386  }
1387  return ($err);
1388  }
1389  /**
1390  * test if the document can be locked
1391  * it is not locked before, and the current user can edit document
1392  *
1393  * @return string empty means user can update else message of the raison
1394  */
1395  final public function CanLockFile()
1396  {
1397  $err = $this->canEdit();
1398  return $err;
1399  }
1400  /**
1401  * @see Doc::canUnLock
1402  * @return boolean true if current user can lock file
1403  */
1404  public function canLock()
1405  {
1406  return ($this->CanLockFile() == "");
1407  }
1408  /**
1409  * @see Doc::canLock
1410  * @return bool true if current user can lock file
1411  */
1412  public function canUnLock()
1413  {
1414  return ($this->CanUnLockFile() == "");
1415  }
1416  /**
1417  * test if the document can be unlocked
1418  * @see Doc::CanLockFile()
1419  * @see Doc::CanUpdateDoc()
1420  * @return string empty means user can update else message of the raison
1421  */
1422  final public function CanUnLockFile()
1423  {
1424  if ($this->userid == 1) return ""; // admin can do anything
1425  $err = "";
1426  if ($this->locked != 0) { // if is already unlocked
1427  if ($this->profid > 0) $err = $this->Control("unlock"); // first control unlock privilege
1428  else $err = _("cannot unlock"); // not control unlock if the document is not controlled
1429 
1430  }
1431  if ($err != "") $err = $this->canEdit();
1432  else {
1433  $err = $this->Control("edit");
1434  if ($err != "") {
1435  if ($this->profid > 0) {
1436  $err = $this->Control("unlock");
1437  }
1438  }
1439  }
1440  return ($err);
1441  }
1442  /**
1443  * test if the document is locked
1444  * @see Doc::canLockFile()
1445  * @param bool $my if true test if it is lock of current user
1446  *
1447  * @return bool true if locked. If $my return true if it is locked by another user
1448  */
1449  final public function isLocked($my = false)
1450  {
1451  if ($my) {
1452  if ($this->userid == 1) {
1453  if ($this->locked == 1) return false;
1454  } elseif (abs($this->locked) == $this->userid) return false;
1455  }
1456  return (($this->locked > 0) || ($this->locked < - 1));
1457  }
1458  /**
1459  * test if the document is confidential
1460  * @return bool true if confidential and current user is not authorized
1461  */
1462  final public function isConfidential()
1463  {
1464  return (($this->confidential > 0) && ($this->controlId($this->profid, 'confidential') != ""));
1465  }
1466  /**
1467  * return the family document where the document comes from
1468  * @deprecated use {@link Doc::getFamilyDocument} instead
1469  * @see Doc::getFamilyDocument
1470  * @return DocFam
1471  */
1472  final public function getFamDoc()
1473  {
1475  return $this->getFamilyDocument();
1476  }
1477  /**
1478  * return the family document where the document comes from
1479  * @api return family odcument
1480  * @return DocFam
1481  */
1482  final public function getFamilyDocument()
1483  {
1484  /*
1485  * @var DocFam $famdoc
1486  */
1487  static $famdoc = null;
1488  if (($famdoc === null) || ($famdoc->id != $this->fromid)) $famdoc = new_Doc($this->dbaccess, $this->fromid);
1489  return $famdoc;
1490  }
1491  /**
1492  * search the first document from its title
1493  * @param string $title the title to search (must be exactly the same title)
1494  * @return int document identifier
1495  */
1497  {
1498 
1499  $query = new QueryDb($this->dbaccess, "Doc");
1500  $query->basic_elem->sup_where = array(
1501  "title='" . $title . "'"
1502  );
1503 
1504  $table1 = $query->Query();
1505  $id = 0;
1506  if ($query->nb > 0) {
1507  $id = $table1[0]->id;
1508 
1509  unset($table1);
1510  }
1511  return $id;
1512  }
1513  /**
1514  * return family parameter
1515  *
1516  * @deprecated use {@link Doc::getFamilyParameterValue} instead
1517  * @see Doc::getFamilyParameterValue
1518  * @param string $idp parameter identifier
1519  * @param string $def default value if parameter not found or if it is null
1520  * @return string parameter value
1521  */
1522  public function getParamValue($idp, $def = "")
1523  {
1524  return $this->getFamilyParameterValue($idp, $def);
1525  }
1526  /**
1527  * return family parameter
1528  *
1529  * @api return family parameter value
1530  * @param string $idp parameter identifier
1531  * @param string $def default value if parameter not found or if it is null
1532  * @note The value of parameter can come from inherited family if its own value is empty.
1533  The value of parameter comes from default configuration value if no one value are set in its family or in a parent family.
1534  the default configuration value comes from inherited family if no default configuration.
1535  In last case, if no values and no configurated default values, the $def argument is returned
1536  * @return string parameter value
1537  */
1538  public function getFamilyParameterValue($idp, $def = "")
1539  {
1540  if (isset($this->_paramValue[$idp])) return $this->_paramValue[$idp];
1541  $r = $this->getParameterFamilyRawValue($idp, $def);
1542  /* @var NormalAttribute $paramAttr */
1543  $paramAttr = $this->getAttribute($idp);
1544  if (!$paramAttr) return $def;
1545  if ($paramAttr->phpfunc != "" && $paramAttr->phpfile == "" && $paramAttr->type !== "enum") {
1546  $this->_paramValue[$idp] = $r;
1547  if ($paramAttr->inArray()) {
1548  $attributes_array = $this->attributes->getArrayElements($paramAttr->fieldSet->id);
1549  $max = 0;
1550  foreach ($attributes_array as $attr) {
1551  $count = count($this->rawValueToArray($this->getFamilyParameterValue($attr->id)));
1552  if ($count > $max) $max = $count;
1553  }
1554  $tmpVal = "";
1555  for ($i = 0; $i < $max; $i++) {
1556  $val = $this->applyMethod($paramAttr->phpfunc, "", $i);
1557  if ($val != $paramAttr->phpfunc) {
1558  if ($tmpVal) $tmpVal.= "\n";
1559  $tmpVal.= $val;
1560  }
1561  }
1562  $r = $tmpVal;
1563  } else {
1564  $val = $this->getValueMethod($paramAttr->phpfunc);
1565  if ($val != $paramAttr->phpfunc) {
1566  $r = $val;
1567  }
1568  }
1569  } else if ($r) {
1570  $this->_paramValue[$idp] = $r;
1571  $r = $this->getValueMethod($r);
1572  }
1573  $this->_paramValue[$idp] = $r;
1574  return $r;
1575  }
1576 
1577  protected function getParameterFamilyRawValue($idp, $def)
1578  {
1579  if (!$this->fromid) return false;
1580  $fdoc = $this->getFamilyDocument();
1581  if (!$fdoc->isAlive()) $r = false;
1582  else $r = $fdoc->getParameterRawValue($idp, $def);
1583  return $r;
1584  }
1585  /**
1586  * return similar documents
1587  *
1588  * @param string $key1 first attribute id to perform search
1589  * @param string $key2 second attribute id to perform search
1590  * @return Doc[] similar documents
1591  */
1592  final public function getDocWithSameTitle($key1 = "title", $key2 = "")
1593  {
1594  $s = new SearchDoc($this->dbaccess, $this->fromid);
1595  $s->overrideViewControl();
1596  $s->addFilter("doctype != 'T'");
1597  if ($this->initid > 0) {
1598  $s->addFilter("initid != %d", $this->initid);
1599  }
1600  $s->addFilter("%s=E'%s'", $key1, $this->getRawValue($key1));
1601  if ($key2 != "") {
1602  $s->addFilter("%s=E'%s'", $key2, $this->getRawValue($key2));
1603  }
1604  $s->setObjectReturn(true);
1605  $s->search();
1606  $dl = $s->getDocumentList();
1607  $t = array();
1608  foreach ($dl as $doc) {
1609  $t[] = clone ($doc);
1610  }
1611  return ($t);
1612  }
1613  /**
1614  * return the latest revision id with the indicated state
1615  * For the user the document is in the trash
1616  * @param string $state wanted state
1617  * @param bool $fixed set to true if not search in current state
1618  * @return int document id (0 if no found)
1619  */
1620  final public function getRevisionState($state, $fixed = false)
1621  {
1622  $ldoc = $this->GetRevisions("TABLE");
1623  $vdocid = 0;
1624 
1625  foreach ($ldoc as $k => $v) {
1626  if ($v["state"] == $state) {
1627  if ((($v["locked"] == - 1) && $fixed) || (!$fixed)) {
1628  $vdocid = $v["id"];
1629  break;
1630  }
1631  }
1632  }
1633  return $vdocid;
1634  }
1635  // --------------------------------------------------------------------
1636  final public function deleteTemporary()
1637  {
1638  // --------------------------------------------------------------------
1639  pg_query($this->init_dbid() , "delete from doc where doctype='T'");
1640  }
1641  /**
1642  * Control if the doc can be deleted
1643  * @access private
1644  * @return string error message, if no error empty string
1645  * @see Doc::Delete()
1646  */
1647  function PreDocDelete()
1648  {
1649  if ($this->doctype == 'Z') return _("already deleted");
1650  if ($this->isLocked(true)) return _("locked");
1651  if ($this->lockdomainid > 0) return sprintf(_("document is booked in domain %s") , $this->getTitle($this->lockdomainid));
1652  $err = $this->Control("delete");
1653 
1654  return $err;
1655  }
1656  /**
1657  * Really delete document from database
1658  * @deprecated use {@link Doc::delete} instead
1659  * @see Doc::delete
1660  * @param bool $nopost set to true if no need tu call postDelete methods
1661  * @return string error message, if no error empty string
1662  */
1663  final public function ReallyDelete($nopost)
1664  {
1666  return $this->_destroy($nopost);
1667  }
1668  /**
1669  * Really delete document from database
1670  * @param bool $nopost set to true if no need tu call postDelete methods
1671  * @return string error message, if no error empty string
1672  */
1673  final private function _destroy($nopost)
1674  {
1675  $err = DbObj::delete($nopost);
1676  if ($err == "") {
1677  $dvi = new DocVaultIndex($this->dbaccess);
1678  $err = $dvi->DeleteDoc($this->id);
1679  if ($this->name != '') {
1680  $this->exec_query(sprintf("delete from docname where name='%s'", pg_escape_string($this->name)));
1681  }
1682  $this->exec_query(sprintf("delete from docfrom where id='%s'", pg_escape_string($this->id)));
1683  }
1684  return $err;
1685  }
1686  /**
1687  * Set the document to zombie state
1688  * For the user the document is in the trash
1689  * @api Delete document
1690  * @param bool $really if true really delete from database
1691  * @param bool $control if false don't control 'delete' acl
1692  * @param bool $nopost if true don't call {@link Doc::postDelete} and {@link Doc::preDelete}
1693  * @return string error message
1694  */
1695  final public function delete($really = false, $control = true, $nopost = false)
1696  {
1697  $err = '';
1698  if ($control) {
1699  // Control if the doc can be deleted
1700  $err = $this->PreDocDelete();
1701  if ($err != '') return $err;
1702  }
1703 
1704  if ($really) {
1705  if ($this->id != "") {
1706  // delete all revision also
1707  global $action;
1708  global $_SERVER;
1709  $appli = $action->parent;
1710  $this->addHistoryEntry(sprintf(_("Destroyed by action %s/%s from %s") , $appli->name, $action->name, isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : 'bash mode') , DocHisto::NOTICE);
1711  $this->addHistoryEntry(_("Document destroyed") , DocHisto::MESSAGE, "DELETE");
1712  $this->addLog('delete', array(
1713  "really" => $really
1714  ));
1715  $rev = $this->GetRevisions();
1716  foreach ($rev as $k => $v) {
1717  $v->_destroy($nopost);
1718  }
1719  }
1720  } else {
1721  // Control if the doc can be deleted
1722  if ($this->doctype == 'Z') $err = _("already deleted");
1723  if ($err != '') return $err;
1724 
1725  if (!$nopost) {
1726  $err = $this->preDelete();
1727  if ($err != '') return $err;
1728  }
1729 
1730  if ($this->doctype != 'Z') {
1731 
1732  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
1733  $this->doctype = 'Z'; // Zombie Doc
1734  $this->locked = - 1;
1735  $this->lmodify = 'D'; // indicate last delete revision
1736  $date = gettimeofday();
1737  $this->revdate = $date['sec']; // Delete date
1738  global $action;
1739  global $_SERVER;
1740 
1741  $appli = $action->parent;
1742  $this->addHistoryEntry(sprintf(_("delete by action %s/%s from %s") , $appli->name, $action->name, isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : 'bash mode') , DocHisto::NOTICE);
1743  $this->addHistoryEntry(_("document deleted") , DocHisto::MESSAGE, "DELETE");
1744  $this->addLog('delete', array(
1745  "really" => $really
1746  ));
1747 
1748  $err = $this->modify(true, array(
1749  "doctype",
1750  "revdate",
1751  "locked",
1752  "owner",
1753  "lmodify"
1754  ) , true);
1755  if ($err == "") {
1756  if (!$nopost) {
1757  $msg = $this->postDelete();
1758  if ($msg != '') {
1759  $this->addHistoryEntry($msg, HISTO_MESSAGE);
1760  }
1761  }
1762  // delete all revision also
1763  $rev = $this->GetRevisions();
1764  foreach ($rev as $k => $v) {
1765  if ($v->doctype != 'Z') {
1766  $v->doctype = 'Z'; // Zombie Doc
1767  if ($v->locked == - 1) $v->modify(true, array(
1768  "doctype"
1769  ) , true);
1770  }
1771  }
1772  }
1773  }
1774  }
1775  return $err;
1776  }
1777  /**
1778  * To restore a document which is in the trash
1779  * @see Doc::undelete
1780  * @deprecated use {@link Doc::undelete} instead
1781  * @return string error message (empty message if no errors);
1782  */
1783  final public function revive()
1784  {
1786  return $this->undelete();
1787  }
1788  /**
1789  * To restore a document which is in the trash
1790  * @api restore deleted document
1791  * @see Doc::delete
1792  * @return string error message (empty message if no errors);
1793  */
1794  final public function undelete()
1795  {
1796  if (($this->control('delete') == "") || ($this->userid == 1)) {
1797  if (!$this->isAlive()) {
1798  $err = $this->preUndelete();
1799  if ($err) return $err;
1800  $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);
1801  if ($err == "") {
1802  if (!$latestId) $err = sprintf(_("document %s [%d] is strange") , $this->title, $this->id);
1803  else {
1804  $previousName = $this->name;
1805  $this->doctype = $this->defDoctype;
1806  $this->locked = 0;
1807  $this->id = $latestId;
1808  $this->name = '';
1809  $this->lmodify = 'Y'; // indicate last restoration
1810  $this->modify(true, array(
1811  "doctype",
1812  "locked",
1813  "lmodify",
1814  "name"
1815  ) , true);
1816  $this->addHistoryEntry(_("revival document") , HISTO_MESSAGE, "REVIVE");
1817  $msg = $this->postUndelete();
1818  if ($msg) $this->addHistoryEntry($msg, HISTO_MESSAGE);
1819  $this->addLog('undelete');
1820  $rev = $this->getRevisions();
1821  /*
1822  * @var Doc $v
1823  */
1824  foreach ($rev as $k => $v) {
1825  if ($v->doctype == 'Z') {
1826  $v->doctype = $v->defDoctype;
1827  $v->name = '';
1828  $err.= $v->modify(true, array(
1829  "doctype",
1830  "name"
1831  ) , true);
1832  }
1833  }
1834  if ($previousName) {
1835  // Reaffect logical name if can be
1836  $this->setLogicalName($previousName);
1837  }
1838  }
1839  }
1840  } else {
1841  $err = sprintf(_("document %s [%d] is not in the trash") , $this->getTitle() , $this->id);
1842  }
1843  } else {
1844  $err = sprintf(_("need privilege delete to restore %s") , $this->getTitle());
1845  }
1846  return $err;
1847  }
1848  /**
1849  * Adaptation of affect Method from DbObj because of inheritance table
1850  * this function is call from QueryDb and all fields can not be instanciate
1851  * @param array $array the data array
1852  * @param bool $more add values from values attributes needed only if cast document
1853  * @param bool $reset reset all values before set and clean private variables
1854  * @return void
1855  */
1856  final public function affect($array, $more = false, $reset = true)
1857  {
1858  if (is_array($array)) {
1859  $this->preAffect($array, $more, $reset);
1860  if ($more) $this->resetMoreValues();
1861  if ($reset) {
1862  foreach ($this->fields as $key) {
1863  $this->$key = null;
1864  }
1865  }
1866  unset($this->uperm); // force recompute privileges
1867  foreach ($array as $k => $v) {
1868  if (!is_integer($k)) {
1869  $this->$k = $v;
1870  }
1871  }
1872  $this->complete();
1873  if ($more) $this->getMoreValues();
1874 
1875  if ($reset) {
1876  $this->_maskApplied = false;
1877  $this->_oldvalue = array();
1878  $this->_paramValue = array();
1879  $this->_setValueCompleteArray = false;
1880  $this->childs = null;
1881  $this->constraintbroken = false;
1882  $this->fathers = null;
1883  $this->hasChanged = false;
1884  $this->htmlFormater = null;
1885  $this->lastRefreshError = '';
1886  $this->mvalues = array();
1887  $this->oooFormater = null;
1888  $this->formaterLevel = 0;
1889  $this->otherFormatter = array();
1890  $this->mid = 0;
1891  $this->svalues = null;
1892  $this->vidNoSendTextToEngine = array();
1893  $this->textsend = array();
1894  }
1895  $this->isset = true;
1896  $this->postAffect($array, $more, $reset);
1897  }
1898  }
1899  /**
1900  * @see Doc::affect()
1901  * @final Doc::complete()
1902  * @access private
1903  * @internal use Doc::postAffect() instead
1904  */
1905  public function complete()
1906  {
1907  }
1908  /**
1909  * @see Doc::affect()
1910  * @param array $data data use to affect document values
1911  * @param bool $more use "values" attribute in case of incomplete data
1912  * @param bool $reset reset all values before set and clean private variables
1913  * @since 3.2.20
1914  * @return void
1915  */
1916  protected function preAffect(array & $data, &$more, &$reset)
1917  {
1918  }
1919  /**
1920  * @see Doc::affect()
1921  * @param array $data data use to affect document values
1922  * @param bool $more use "values" attribute in case of incomplete data
1923  * @param bool $reset reset all values before set and clean private variables
1924  * @since 3.2.20
1925  * @return void
1926  */
1927  protected function postAffect(array $data, $more, $reset)
1928  {
1929  }
1930  /**
1931  * Set to default values before add new doc
1932  * @return void
1933  */
1934  function init()
1935  {
1936  $this->isset = false;
1937  $this->id = "";
1938  $this->initid = "";
1939  $nattr = $this->GetNormalAttributes();
1940  foreach ($nattr as $k => $v) {
1941  if (isset($this->$k) && ($this->$k != "")) $this->$k = "";
1942  }
1943  }
1944  // --------------------------------------------------------------------
1945  function description()
1946  {
1947  // --------------------------------------------------------------------
1948  return $this->title . " - " . $this->revision;
1949  }
1950  /**
1951  * use for system purpose
1952  * prefer ::getFromDoc instead
1953  * @return int[]
1954  */
1955  final public function getFathersDoc()
1956  {
1957  // --------------------------------------------------------------------
1958  // Return array of father doc id : class document
1959  if ($this->fathers === null) {
1960 
1961  $this->fathers = array();
1962  if ($this->fromid > 0) {
1963  $fdoc = $this->getFamilyDocument();
1964  $this->fathers = $fdoc->GetFathersDoc();
1965  array_push($this->fathers, $this->fromid);
1966  }
1967  }
1968  return $this->fathers;
1969  }
1970  /**
1971  * Return array of fathers doc id : class document
1972  * @return int[]
1973  */
1974  final public function getFromDoc()
1975  {
1976  return $this->attributes->fromids;
1977  }
1978  /**
1979  * Return array of child family raw documents
1980  * @param int $id if -1 use child for current document else for the family identifier set
1981  * @param bool $controlcreate set to true to not return documents which cannot be created by current user
1982  * @return array raw docfam values
1983  */
1984  final public function getChildFam($id = - 1, $controlcreate = false)
1985  {
1986  if ($id == 0) return array();
1987  if (($id != - 1) || (!isset($this->childs))) {
1988  include_once ("FDL/Class.SearchDoc.php");
1989  if ($id == - 1) $id = $this->id;
1990  if (!isset($this->childs)) $this->childs = array();
1991 
1992  $s = new SearchDoc($this->dbaccess, -1);
1993  $s->addFilter("fromid = " . $id);
1994  $s->overrideViewControl();
1995  $table1 = $s->search();
1996  if ($table1) {
1997  foreach ($table1 as $k => $v) {
1998  if ((!$controlcreate) || controlTdoc($v, "icreate")) {
1999  $this->childs[$v["id"]] = $v;
2000  }
2001  $this->GetChildFam($v["id"], $controlcreate);
2002  }
2003  }
2004  }
2005  return $this->childs;
2006  }
2007  /**
2008  * return all revision documents
2009  * @param string $type LIST|TABLE il LIST return Doc object else if TABLE raw documents
2010  * @param int $limit limit of revision (by default the 200 latest revisions)
2011  * @return Doc[]|array
2012  */
2013  final public function getRevisions($type = "LIST", $limit = 200)
2014  {
2015  // Return the document revision
2016  $query = new QueryDb($this->dbaccess, strtolower(get_class($this)));
2017  //$query->AddQuery("revision <= ".$this->revision);
2018  $query->AddQuery("initid = " . $this->initid);
2019  $query->order_by = "revision DESC LIMIT $limit";
2020 
2021  $rev = $query->Query(0, 0, $type);
2022  if ($query->nb == 0) return array();
2023  return $rev;
2024  }
2025  /** get Latest Id of document
2026  *
2027  * @deprecated use {@link Doc::getLatestId} instead
2028  * @param bool $fixed if true latest fixed revision
2029  * @param bool $forcequery if true force recompute of id (use it in case of modification by another program)
2030  * @see Doc::getLatestId
2031  * @return int identifier of latest revision
2032  */
2033  final public function latestId($fixed = false, $forcequery = false)
2034  {
2036  return $this->getLatestId($fixed, $forcequery);
2037  }
2038  /** get Latest Id of document
2039  *
2040  * @api get latest id of document
2041  * @param bool $fixed if true latest fixed revision
2042  * @param bool $forcequery if true force recompute of id (use it in case of modification by another program)
2043  * @return int identifier of latest revision
2044  */
2045  final public function getLatestId($fixed = false, $forcequery = false)
2046  {
2047  if ($this->id == "") return false;
2048  if (!$forcequery) {
2049  if (($this->locked != - 1) && (!$fixed)) return $this->id;
2050  if ($fixed && ($this->lmodify == "L")) return $this->id;
2051  }
2052  if (!$fixed) return getLatestDocId($this->dbaccess, $this->initid);
2053  $query = new QueryDb($this->dbaccess, strtolower(get_class($this)));
2054  $query->AddQuery("initid = " . $this->initid);
2055  if ($fixed) $query->AddQuery("lmodify = 'L'");
2056  elseif ($this->doctype != 'Z') $query->AddQuery("locked != -1");
2057  else {
2058  $query->order_by = "id desc";
2059  }
2060  $rev = $query->Query(0, 2, "TABLE");
2061 
2062  if ($this->doctype != 'Z') {
2063  if (count($rev) > 1) addWarningMsg(sprintf("document %d : multiple alive revision", $this->initid));
2064  }
2065  return $rev[0]["id"];
2066  }
2067  /**
2068  * get version of document
2069  * can be redefined by child document classes if needed
2070  * @return string
2071  */
2072  public function getVersion()
2073  {
2074  $tversion = array();
2075  if (isset($this->attributes->attr)) {
2076  foreach ($this->attributes->attr as $k => $v) {
2077  if ((get_class($v) == "NormalAttribute") && ($v->getOption("version") == "yes")) {
2078  $tversion[] = $this->getRawValue($v->id);
2079  }
2080  }
2081  }
2082  if (count($tversion) > 0) $version = implode(" ", $tversion);
2083  else $version = $this->version;
2084  return $version;
2085  }
2086  /**
2087  * return the string label text for a id (label depends of current user locale)
2088  * @param string $idAttr attribute identifier
2089  * @return string
2090  */
2091  final public function getLabel($idAttr)
2092  {
2093  if (isset($this->attributes->attr[$idAttr])) return $this->attributes->attr[$idAttr]->getLabel();
2094  return _("unknow attribute");
2095  }
2096  /**
2097  * return the property value like id, initid, revision, ...
2098  * @deprecated use {@link Doc::getPropertyValue} instead
2099  * @see Doc::getPropertyValue
2100  * @param string $prop property identifier
2101  * @return string false if not an property
2102  */
2103  final public function getProperty($prop)
2104  {
2106  return $this->getPropertyValue($prop);
2107  }
2108  /**
2109  * return the property value like id, initid, revision, ...
2110  * @api get property value
2111  * @param string $prop property identifier
2112  * @return string false if not an property
2113  */
2114  final public function getPropertyValue($prop)
2115  {
2116  $prop = trim(strtolower($prop));
2117  if (!in_array($prop, $this->fields)) return false;
2118  if (isset($this->fields[$prop])) return false; // it's an attribute
2119  return $this->$prop;
2120  }
2121  /**
2122  * Return the tag object for the document
2123  *
2124  * @throws Dcp\Exception
2125  * @return TagManager &$tag object reference use to modify tags
2126  */
2127  final public function &tag()
2128  {
2129  /*
2130  * @var TagManager $tag
2131  */
2132  static $tag = null;
2133 
2134  if (empty($tag) || $tag->docid != $this->initid) {
2135  if (class_exists("TagManager")) {
2136  $tag = new TagManager($this, $this->initid);
2137  } else {
2138  throw new Dcp\Exception("Need install dynacase-tags module.\n");
2139  }
2140  }
2141  return $tag;
2142  }
2143  /**
2144  * return the attribute object for a id
2145  * the attribute can be defined in fathers
2146  * @api get attribute object
2147  * @param string $idAttr attribute identifier
2148  * @param BasicAttribute &$oa object reference use this if want to modify attribute
2149  * @param bool $useMask set to false to not apply mask if needed (quick access mode)
2150  * @return BasicAttribute|bool|NormalAttribute
2151  */
2152  final public function &getAttribute($idAttr, &$oa = null, $useMask = true)
2153  {
2154  if ($idAttr !== Adoc::HIDDENFIELD) {
2155  $idAttr = strtolower($idAttr);
2156  }
2157  if ($useMask) {
2158  $this->getAttributes($useMask);
2159  }
2160  if (isset($this->attributes->attr[$idAttr])) {
2161  $oa = $this->attributes->attr[$idAttr];
2162  } else {
2163  $oa = false;
2164  }
2165 
2166  return $oa;
2167  }
2168  /**
2169  * return all the attributes object
2170  * the attribute can be defined in fathers
2171  * @param bool $useMask set to false to not apply mask if needed (quick access mode)
2172  * @return BasicAttribute[]
2173  */
2174  final public function &getAttributes($useMask = true)
2175  {
2176  $fromname = ($this->doctype == 'C') ? $this->name : $this->fromname;
2177  $aFromName = isset($this->attributes->fromname) ? $this->attributes->fromname : '';
2178  if ($aFromName != $fromname) {
2179  // reset when use partial cache
2180  $fromid = ($this->doctype == 'C') ? $this->id : $this->fromid;
2181  $adocClassName = "ADoc" . $fromid;
2182  $classname = "Doc" . $fromid;
2183  $GEN = getGen($this->dbaccess);
2184  $includePath = "FDL$GEN/Class.$classname.php";
2185  if (file_exists($includePath)) {
2186  include_once ($includePath);
2187  $this->attributes = new $adocClassName();
2188  }
2189  }
2190  if ($useMask && !$this->_maskApplied) {
2191  $this->ApplyMask();
2192  reset($this->attributes->attr);
2193  }
2194  return $this->attributes->attr;
2195  }
2196  /**
2197  * retrieve first compatible view from default view control
2198  * @param bool $edition if true edition view else consultation view
2199  * @param string $extract [id|mask|all]
2200  * @return array|int view definition "cv_idview", "cv_mskid"
2201  */
2202  final public function getDefaultView($edition = false, $extract = "all")
2203  {
2204  if ($this->cvid > 0) {
2205  // special controlled view
2206 
2207  /**
2208  * @var \Dcp\Family\CVDoc $cvdoc
2209  */
2210  $cvdoc = new_Doc($this->dbaccess, $this->cvid);
2211  $cvdoc = clone $cvdoc;
2212  $cvdoc->Set($this);
2213 
2214  $view = $cvdoc->getPrimaryView($edition);
2215 
2216  if ($view) {
2217  switch ($extract) {
2218  case 'id':
2219  return $view["cv_idview"];
2220  case 'mask':
2221  return $view["cv_mskid"];
2222  default:
2223  return $view;
2224  }
2225  }
2226  }
2227  return 0;
2228  }
2229  /**
2230  * set visibility mask
2231  *
2232  * @param int $mid mask ident
2233  * @return string error message
2234  */
2235  final public function setMask($mid)
2236  {
2237  $this->mid = $mid;
2238  if (isset($this->attributes->attr)) {
2239  // reinit mask before apply
2240  foreach ($this->attributes->attr as $k => $v) {
2241  if ($this->attributes->attr[$k] !== null) {
2242  $this->attributes->attr[$k]->mvisibility = $v->visibility;
2243  }
2244  }
2245  }
2246  return $this->ApplyMask($mid);
2247  }
2248  /**
2249  * apply visibility mask
2250  *
2251  * @param int $mid mask ident, if not set it is found from possible workflow
2252  * @param bool $force set to true to force reapply mask even it is already applied
2253  * @return string error message
2254  */
2255  final public function applyMask($mid = 0, $force = false)
2256  {
2257  // copy default visibilities
2258  $err = '';
2259  $this->_maskApplied = true;
2260  $oas = $this->getAttributes();
2261  if (is_array($oas)) {
2262  foreach ($oas as $k => $v) {
2263  if ($oas[$k]) $oas[$k]->mvisibility = ComputeVisibility($v->visibility, (empty($v->fieldSet)) ? '' : $v->fieldSet->mvisibility, (!empty($v->fieldSet->fieldSet)) ? $v->fieldSet->fieldSet->mvisibility : '');
2264  }
2265  }
2266  $argMid = $mid;
2267  if ((!$force) && (($this->doctype == 'C') || (($this->doctype == 'T') && ($mid == 0)))) return '';
2268  // modify visibilities if needed
2269  if ((!is_numeric($mid)) && ($mid != "")) {
2270  $imid = getIdFromName($this->dbaccess, $mid);
2271  if (!$imid) {
2272  $err = ErrorCode::getError('DOC1004', $argMid, $this->getTitle());
2273  return $err;
2274  } else {
2275  $mid = $imid;
2276  }
2277  }
2278 
2279  if ($mid == 0) $mid = $this->mid;
2281  if ($this->cvid) {
2282  /**
2283  * @var \Dcp\Family\CVDoc $cvdoc
2284  */
2285  $cvdoc = new_Doc($this->dbaccess, $this->cvid);
2286  if ($cvdoc->isAlive()) {
2287  $cvdoc = clone $cvdoc;
2288  $cvdoc->Set($this);
2289  $vid = $this->getDefaultView(($mid == Doc::USEMASKCVEDIT) , "id");
2290  if ($vid != '') {
2291  $tview = $cvdoc->getView($vid);
2292  $mid = ($tview !== false) ? $tview["CV_MSKID"] : 0;
2293  }
2294  }
2295  }
2297  $mid = 0;
2298  }
2299  }
2300  if ($mid == 0) {
2301  if (($this->wid > 0) && ($this->wid != $this->id)) {
2302  // search mask from workflow
2303 
2304  /**
2305  * @var $wdoc WDoc
2306  */
2307  $wdoc = new_Doc($this->dbaccess, $this->wid);
2308  if ($wdoc->isAlive()) {
2309  if ($this->id == 0) {
2310  $wdoc->set($this);
2311  }
2312  $mid = $wdoc->getStateMask($this->state);
2313  if ((!is_numeric($mid)) && ($mid != "")) $mid = getIdFromName($this->dbaccess, $mid);
2314  }
2315  }
2316  }
2317 
2318  if ($mid) {
2319  if (!$argMid) $argMid = $mid;
2320  /**
2321  * @var \Dcp\Family\MASK $mdoc
2322  */
2323  $mdoc = new_Doc($this->dbaccess, $mid);
2324  if ($mdoc->isAlive()) {
2325  if (is_a($mdoc, '\Dcp\Family\Mask')) {
2326 
2327  $maskFam = $mdoc->getRawValue("msk_famid");
2328  if (!in_array($maskFam, $this->getFromDoc())) {
2329  $err = ErrorCode::getError('DOC1002', $argMid, $this->getTitle() , getNameFromId($this->dbaccess, $maskFam));
2330  } else {
2331  $tvis = $mdoc->getVisibilities();
2332  foreach ($tvis as $k => $v) {
2333  if (isset($oas[$k])) {
2334  if ($v != "-") $oas[$k]->mvisibility = $v;
2335  }
2336  }
2337  $tdiff = array_diff(array_keys($oas) , array_keys($tvis));
2338  // compute frame before because has no order
2339  foreach ($tdiff as $k) {
2340  $v = $oas[$k];
2341  if ($v->type == "frame") {
2342  $oas[$k]->mvisibility = ComputeVisibility($v->visibility, isset($v->fieldSet) ? $v->fieldSet->mvisibility : '', '');
2343  }
2344  }
2345  foreach ($tdiff as $k) {
2346  $v = $oas[$k];
2347  if ($v->type == "array") {
2348  $oas[$k]->mvisibility = ComputeVisibility($v->visibility, isset($v->fieldSet) ? $v->fieldSet->mvisibility : '', isset($v->fieldSet->fieldSet) ? $v->fieldSet->fieldSet->mvisibility : '');
2349  }
2350  }
2351  // recompute loosed attributes
2352  foreach ($tdiff as $k) {
2353  $v = $oas[$k];
2354  if ($v->type != "frame") {
2355  $oas[$k]->mvisibility = ComputeVisibility($v->visibility, isset($v->fieldSet) ? $v->fieldSet->mvisibility : '', isset($v->fieldSet->fieldSet) ? $v->fieldSet->fieldSet->mvisibility : '');
2356  }
2357  }
2358  // modify needed attribute also
2359  $tneed = $mdoc->getNeedeeds();
2360  foreach ($tneed as $k => $v) {
2361  if (isset($oas[$k])) {
2362  if ($v == "Y") $oas[$k]->needed = true;
2363  else if ($v == "N") $oas[$k]->needed = false;
2364  }
2365  }
2366  }
2367  } else {
2368  $err = ErrorCode::getError('DOC1001', $argMid, $mdoc->fromname, $this->getTitle());
2369  }
2370  } else {
2371  $err = ErrorCode::getError('DOC1000', $argMid, $this->getTitle());
2372  }
2373  }
2374  if (!empty($this->attributes->attr)) {
2375  $this->attributes->orderAttributes();
2376  }
2377 
2378  if ($err) error_log($err);
2379  return $err;
2380  }
2381  /**
2382  * return all the attributes except frame & menu & action
2383  * @param boolean $onlyopt get only optional attributes
2384  *
2385  * @return NormalAttribute[]
2386  */
2387  final public function getNormalAttributes($onlyopt = false)
2388  {
2389  if (!$this->_maskApplied) $this->ApplyMask();
2390  if ((isset($this->attributes)) && (method_exists($this->attributes, "GetNormalAttributes"))) return $this->attributes->GetNormalAttributes($onlyopt);
2391  else return array();
2392  }
2393  /**
2394  * return frame attributes
2395  *
2396  * @return FieldSetAttribute[]
2397  */
2398  final public function getFieldAttributes()
2399  {
2400  if (!$this->_maskApplied) $this->ApplyMask();
2401  $tsa = array();
2402 
2403  foreach ($this->attributes->attr as $k => $v) {
2404  if (is_object($v) && (get_class($v) == "FieldSetAttribute")) $tsa[$v->id] = $v;
2405  }
2406  return $tsa;
2407  }
2408  /**
2409  * return action attributes
2410  *
2411  * @return ActionAttribute[]
2412  */
2413  final public function getActionAttributes()
2414  {
2415  if (!$this->_maskApplied) $this->ApplyMask();
2416  $tsa = array();
2417  if (isset($this->attributes)) {
2418  $at = $this->attributes->GetActionAttributes();
2419  foreach ($at as $k => $v) {
2420  if ($v->mvisibility != 'H') $tsa[$v->id] = $v;
2421  }
2422  }
2423  return $tsa;
2424  }
2425  /**
2426  * return all the attributes object for abstract
2427  * the attribute can be defined in fathers
2428  * @return NormalAttribute[]
2429  */
2430  final public function getAbstractAttributes()
2431  {
2432  if (!$this->_maskApplied) $this->ApplyMask();
2433  $tsa = array();
2434 
2435  if (isset($this->attributes->attr)) {
2436  foreach ($this->attributes->attr as $k => $v) {
2437  /*
2438  * @var NormalAttribute $v
2439  */
2440  if (is_object($v) && (get_class($v) == "NormalAttribute") && ($v->usefor != 'Q') && ($v->isInAbstract)) $tsa[$v->id] = $v;
2441  }
2442  }
2443  return $tsa;
2444  }
2445  /**
2446  * return all the attributes object for title
2447  * the attribute can be defined in fathers
2448  * @return NormalAttribute[]
2449  */
2450  final public function getTitleAttributes()
2451  {
2452  if (!$this->_maskApplied) $this->ApplyMask();
2453  $tsa = array();
2454  if (isset($this->attributes->attr)) {
2455  foreach ($this->attributes->attr as $k => $v) {
2456  /*
2457  * @var NormalAttribute $v
2458  */
2459  if ((get_class($v) == "NormalAttribute") && ($v->isInTitle)) $tsa[$v->id] = $v;
2460  }
2461  }
2462  return $tsa;
2463  }
2464  /**
2465  * return all the attributes that can be use in profil
2466  *
2467  * @return BasicAttribute[]
2468  */
2469  final public function getProfilAttributes()
2470  {
2471  if (!$this->_maskApplied) $this->ApplyMask();
2472  $tsa = array();
2473  $tsb = array();
2474  $wopt = false;
2475  if (isset($this->attributes->attr)) {
2476  foreach ($this->attributes->attr as $k => $v) {
2477  if ($v->type == "docid") {
2478  if ($v->getOption("isuser") != "") {
2479  if ($v->getOption("isuser") == "yes") $tsb[$v->id] = $v;
2480  $wopt = true;
2481  }
2482  } elseif ($v->type == "account") {
2483  $wopt = true;
2484  if ($v->getOption("isuser") != "no") $tsb[$v->id] = $v;
2485  }
2486  }
2487  }
2488  if ($wopt) return $tsb;
2489  return $tsa;
2490  }
2491  /**
2492  * return all the attributes object for to e use in edition
2493  * the attribute can be defined in fathers
2494  * @param bool $onlyopt deprecated arguments
2495  * @return NormalAttribute[]
2496  */
2497  final public function getInputAttributes($onlyopt = false)
2498  {
2499  if (!$this->_maskApplied) $this->ApplyMask();
2500  $tsa = array();
2501 
2502  foreach ($this->attributes->attr as $k => $v) {
2503  if ((get_class($v) == "NormalAttribute") && (!$v->inArray()) && ($v->mvisibility != "I")) { // I means not editable
2504  if ((($this->usefor == "Q") && ($v->usefor == "Q")) || (($this->usefor != "Q") && ((($v->usefor != "Q") && (!$onlyopt)) || (($v->usefor == "O") && ($onlyopt))))) $tsa[$v->id] = $v; //special parameters
2505 
2506  }
2507  }
2508  return $tsa;
2509  }
2510  /**
2511  * return all the parameters definition for its family
2512  * the attribute can be defined in fathers
2513  * @return NormalAttribute[]
2514  */
2515  final public function getParamAttributes()
2516  {
2517 
2518  if (!$this->_maskApplied) $this->ApplyMask();
2519  if ((isset($this->attributes)) && (method_exists($this->attributes, "getParamAttributes"))) return $this->attributes->getParamAttributes();
2520  else return array();
2521  }
2522  /**
2523  * return all the attributes object for abstract
2524  * the attribute can be defined in fathers
2525  * @param bool $onlyfile set to true if don't want images
2526  * @return NormalAttribute[]
2527  */
2528  final public function getFileAttributes($onlyfile = false)
2529  {
2530  if (!$this->_maskApplied) $this->ApplyMask();
2531  $tsa = array();
2532 
2533  foreach ($this->attributes->attr as $k => $v) {
2534  if ((get_class($v) == "NormalAttribute") && ($v->usefor != 'Q') && ((($v->type == "image") && (!$onlyfile)) || ($v->type == "file"))) $tsa[$v->id] = $v;
2535  }
2536  return $tsa;
2537  }
2538  /**
2539  * return files properties of file attributes
2540  *
2541  * @return array
2542  */
2543  final public function getFilesProperties()
2544  {
2545  $dvi = new DocVaultIndex($this->dbaccess);
2546  $tvid = $dvi->getVaultIds($this->id);
2547  $tinfo = array();
2548  $vf = newFreeVaultFile($this->dbaccess);
2549  foreach ($tvid as $vid) {
2550  $info = null;
2551  $err = $vf->Retrieve($vid, $info);
2552  $t = get_object_vars($info);
2553  $t["vid"] = $vid;
2554  if ($err == "") $tinfo[] = $t;
2555  }
2556 
2557  return $tinfo;
2558  }
2559  /**
2560  * verify if has some files waiting conversion
2561  *
2562  * @return bool
2563  */
2564  final public function hasWaitingFiles()
2565  {
2566  if (!\Dcp\Autoloader::classExists('Dcp\TransformationEngine\Client')) {
2567  return false;
2568  }
2569  $dvi = new DocVaultIndex($this->dbaccess);
2570  $tvid = $dvi->getVaultIds($this->id);
2571  if (count($tvid) == 0) return false;
2572  $sql = sprintf("select id_file from vaultdiskstorage where teng_state=%d and %s limit 1", \Dcp\TransformationEngine\Client::status_waiting, getSqlCond($tvid, "id_file", true));
2573  simpleQuery($this->dbaccess, $sql, $waiting, true, true);
2574  return ($waiting != false);
2575  }
2576  /**
2577  * reset Conversion of file
2578  * update $attrid_txt table column
2579  * @param string $attrid file attribute identifier
2580  * @param int $index index in case of multiple attribute
2581  * @apiExpose
2582  * @return string error message
2583  */
2584  public function resetConvertVaultFile($attrid, $index)
2585  {
2586  $err = $this->canEdit();
2587  if ($err) {
2588  return $err;
2589  }
2590  $val = $this->getMultipleRawValues($attrid, false, $index);
2591  if (($index == - 1) && (count($val) == 1)) {
2592  $val = $val[0];
2593  }
2594 
2595  if ($val) {
2596  $info = $this->getFileInfo($val);
2597  if ($info) {
2598  $ofout = new VaultDiskStorage($this->dbaccess, $info["id_file"]);
2599  if ($ofout->isAffected()) {
2600  $err = $ofout->delete();
2601  }
2602  }
2603  }
2604  return $err;
2605  }
2606  /**
2607  * send a request to TE to convert files
2608  * update $attrid_txt table column
2609  * waiting end of conversion
2610  * @param string $va value of file attribute like mime|vid|name
2611  * @param string $engine the name of transformation
2612  * @param bool $isimage set true if it is an image (error returns is not same)
2613  * @return string new file reference
2614  */
2615  public function convertVaultFile($va, $engine, $isimage = false)
2616  {
2617  include_once ("FDL/Lib.Vault.php");
2618  $engine = strtolower($engine);
2619  $value = '';
2620  if (is_array($va)) return "";
2621  $err = '';
2622  if (getParam("TE_ACTIVATE") == "yes" && \Dcp\Autoloader::classExists('Dcp\TransformationEngine\Client')) {
2623  if (preg_match(PREGEXPFILE, $va, $reg)) {
2624  $vidin = $reg[2];
2625  $vidout = 0;
2626  $info = vault_properties($vidin, $engine);
2627  // in case of server not reach : try again
2628  if (!is_object($info)) {
2629  // not found : create it
2630  $info = new VaultFileInfo();
2631  }
2632  if ($info->teng_state == \Dcp\TransformationEngine\Client::error_connect) {
2633  $info->teng_state = \Dcp\TransformationEngine\Client::status_inprogress;
2634  }
2635  if ((!$info->teng_vid) || ($info->teng_state == \Dcp\TransformationEngine\Client::status_inprogress)) {
2636  $vf = newFreeVaultFile($this->dbaccess);
2637  if (!$info->teng_vid) {
2638  // create temporary file
2639  $value = sprintf(_("conversion %s in progress") , $engine);
2640  if ($isimage) {
2641  $filename = DEFAULT_PUBDIR . "/Images/workinprogress.png";
2642  } else $filename = uniqid(getTmpDir() . "/conv") . ".txt";
2643  file_put_contents($filename, $value);
2644  $vidout = 0;
2645  $err = $vf->Store($filename, false, $vidout, "", $engine, $vidin);
2646  if ($err) {
2647  $this->addHistoryEntry(sprintf(_("convert file %s as %s failed : %s") , $info->name, $engine, $err) , HISTO_ERROR);
2648  error_log($err);
2649  return '';
2650  }
2651  $info = vault_properties($vidin);
2652  if (!$isimage) {
2653  unlink($filename);
2654  $mime = 'text/plain';
2655  } else {
2656  $mime = 'image/png';
2657  }
2658 
2659  $value = "$mime|$vidout";
2660  if ($err == "") $vf->rename($vidout, sprintf(_("conversion of %s in progress") . ".%s", $info->name, $engine));
2661 
2662  $this->addHistoryEntry("value $engine : $value");
2663  /* Do not index temporary vid "vidout" while waiting for transformation result */
2664  $this->vidNoSendTextToEngine[$vidout] = true;
2665  } else {
2666  if ($err == "") {
2667  $info1 = vault_properties($vidin);
2668  $vidout = $info->id_file;
2669  $vf->rename($vidout, sprintf(_("update of %s in progress") . ".%s", $info1->name, $engine));
2670  $value = $info->mime_s . '|' . $info->id_file;
2671  }
2672  }
2673 
2674  $err = vault_generate($this->dbaccess, $engine, $vidin, $vidout, $isimage, $this->initid);
2675  if ($err != "") {
2676  $this->addHistoryEntry(sprintf(_("convert file %s as %s failed : %s") , $info->name, $engine, $err) , HISTO_ERROR);
2677  }
2678  } else {
2679  if ($isimage) {
2680  if ($info->teng_state < 0) {
2681  if ($info->teng_state == \Dcp\TransformationEngine\Client::error_convert) $value = "convertfail.png";
2682  else $value = "convertimpossible.png";
2683  } else {
2684  if ($info->teng_state == \Dcp\TransformationEngine\Client::status_done) $value = $info->mime_s . '|' . $info->id_file . '|' . $info->name;
2685  }
2686  } else {
2687  $value = $info->mime_s . '|' . $info->id_file . '|' . $info->name;
2688  }
2689  /* Do not index vid with failed or pending transformations */
2690  if ($info->teng_state != \Dcp\TransformationEngine\Client::status_done) {
2691  $this->vidNoSendTextToEngine[$info->id_file] = true;
2692  }
2693  }
2694  }
2695  }
2696  return $value;
2697  }
2698  /**
2699  * Return all the attributes object for popup menu
2700  * the attribute can be defined in fathers
2701  * @param bool $viewhidden set to true if need all defined menu (hidden also)
2702  * @return MenuAttribute[]
2703  */
2704  function getMenuAttributes($viewhidden = false)
2705  {
2706  if (!$this->_maskApplied) $this->ApplyMask();
2707  $tsa = array();
2708 
2709  reset($this->attributes->attr);
2710  foreach ($this->attributes->attr as $k => $v) {
2711  if (((get_class($v) == "MenuAttribute")) && (($v->mvisibility != 'H') || $viewhidden)) $tsa[$v->id] = $v;
2712  }
2713  return $tsa;
2714  }
2715  /**
2716  * return all the necessary attributes
2717  * @param bool $parameters set to true if want parameters instead of attributes
2718  * @return NormalAttribute[]
2719  */
2720  final public function getNeededAttributes($parameters = false)
2721  {
2722  $tsa = array();
2723 
2724  if ($parameters) {
2725  foreach ($this->attributes->attr as $k => $v) {
2726  /*
2727  * @var NormalAttribute $v
2728  */
2729  if ((get_class($v) == "NormalAttribute") && ($v->needed) && ($v->usefor == 'Q')) $tsa[$v->id] = $v;
2730  }
2731  } else {
2732  if (!$this->_maskApplied) $this->ApplyMask();
2733  foreach ($this->attributes->attr as $k => $v) {
2734  /*
2735  * @var NormalAttribute $v
2736  */
2737  if ((get_class($v) == "NormalAttribute") && ($v->needed) && ($v->usefor != 'Q')) $tsa[$v->id] = $v;
2738  }
2739  }
2740  return $tsa;
2741  }
2742  /**
2743  * verify if all needed attributes are set
2744  *
2745  * @return string error message if some needed attributes are empty
2746  */
2747  final public function isCompleteNeeded()
2748  {
2749  $tsa = $this->GetNeededAttributes();
2750  $err = "";
2751  foreach ($tsa as $k => $v) {
2752  if ($v->inArray()) {
2753  /* Check for empty cells in columns */
2754  $columnValues = $this->getMultipleRawValues($v->id);
2755  foreach ($columnValues as $value) {
2756  if ($value == "") {
2757  $err.= sprintf(_("%s needed\n") , $v->getLabel());
2758  /* Do not report multiple errors for the same column */
2759  break;
2760  }
2761  }
2762  } else {
2763  if ($this->getRawValue($v->id) == "") {
2764  $err.= sprintf(_("%s needed\n") , $v->getLabel());
2765  }
2766  }
2767  }
2768  return $err;
2769  }
2770  /**
2771  * verify if attribute equals $b
2772  * to be use in constraint
2773  * @param string $a attribute identifier
2774  * @param string $b value
2775  * @return bool
2776  */
2777  final public function equal($a, $b)
2778  {
2779  return ($this->$a == $b);
2780  }
2781  /**
2782  * return list of attribut which can be exported
2783  * @param bool $withfile true if export also file attribute
2784  * @param bool $forcedefault if true preference FREEDOM_EXPORTCOLS are not read
2785  * @return NormalAttribute[]
2786  */
2787  final public function getExportAttributes($withfile = false, $forcedefault = false)
2788  {
2789  include_once ("GENERIC/generic_util.php");
2790  global $action;
2791 
2792  if ($this->doctype == 'C') $famid = $this->id;
2793  else $famid = $this->fromid;
2794  if (!$this->_maskApplied) $this->ApplyMask();
2795  $tsa = array();
2796  if (isset($this->attributes->attr)) {
2797  $pref = getFamilyParameter($action, $famid, "FREEDOM_EXPORTCOLS");
2798  if ((!$forcedefault) && ($pref != "")) {
2799 
2800  $tpref = explode(";", $pref);
2801 
2802  foreach ($this->attributes->attr as $k => $v) {
2803  if (in_array($v->id, $tpref)) {
2804  $tsa[$v->id] = $v;
2805  }
2806  }
2807  } else {
2808  foreach ($this->attributes->attr as $k => $v) {
2809  if (get_class($v) == "NormalAttribute" && $v->usefor != 'Q') {
2810 
2811  if (($v->type != "array") && ($withfile || (($v->type != "image") && ($v->type != "file")))) $tsa[$v->id] = $v;
2812  }
2813  }
2814  }
2815  }
2816  return $tsa;
2817  }
2818  /**
2819  * return all the attributes object for import
2820  * @return NormalAttribute[]
2821  */
2822  final public function getImportAttributes()
2823  {
2824 
2825  if (!$this->_maskApplied) $this->ApplyMask();
2826  $tsa = array();
2827  if (!empty($this->attributes->attr)) {
2828  $this->attributes->orderAttributes();
2829  }
2830  $tattr = $this->attributes->attr;
2831  foreach ($tattr as $k => $v) {
2832  /*
2833  * @var NormalAttribute $v
2834  */
2835 
2836  if ((get_class($v) == "NormalAttribute") && (($v->mvisibility == "W") || ($v->mvisibility == "O") || ($v->type == "docid")) && ($v->type != "array")) {
2837 
2838  if (preg_match("/\(([^\)]+)\):(.+)/", $v->phpfunc, $reg)) {
2839 
2840  $aout = explode(",", $reg[2]);
2841  foreach ($aout as $ka => $va) {
2842  $ra = $this->GetAttribute($va);
2843  if ($ra) $tsa[strtolower($va) ] = $ra;
2844  }
2845  }
2846  $tsa[$v->id] = $v;
2847  }
2848  }
2849 
2850  return $tsa;
2851  }
2852  /**
2853  * return all the attributes which can be sorted
2854  * @return NormalAttribute[]
2855  */
2856  public function getSortAttributes()
2857  {
2858  $tsa = array();
2859  $nattr = $this->GetNormalAttributes();
2860  reset($nattr);
2861 
2862  foreach ($nattr as $k => $a) {
2863  if ($a->repeat || ($a->visibility == "I") || ($a->visibility == "O") || ($a->type == "longtext") || ($a->type == "xml") || ($a->type == "htmltext") || ($a->type == "image") || ($a->type == "file") || ($a->getOption('sortable') != 'asc' && $a->getOption('sortable') != 'desc')) {
2864  continue;
2865  }
2866  $tsa[$a->id] = $a;
2867  }
2868  return $tsa;
2869  }
2870  /**
2871  * recompute the title from attribute values
2872  */
2873  final public function refreshTitle()
2874  {
2875 
2876  if ($this->doctype == 'C') return; // no refresh for family document
2877  $ltitle = $this->GetTitleAttributes();
2878 
2879  $title1 = "";
2880  foreach ($ltitle as $k => $v) {
2881  if ($this->getRawValue($v->id) != "") {
2882  if ($v->inArray() && ($v->getOption('multiple') == 'yes')) {
2883  $title1.= mb_trim(str_replace("<BR>", " ", $this->getRawValue($v->id))) . " ";
2884  } else $title1.= $this->getRawValue($v->id) . " ";
2885  }
2886  }
2887  /* Replace control chars with spaces, and limit title to 256 chars */
2888  if (mb_trim($title1) != "") $this->title = mb_substr(mb_trim(preg_replace('/\p{Cc}/u', ' ', $title1)) , 0, 255);
2889  $this->title = mb_substr(mb_trim(preg_replace('/\p{Cc}/u', ' ', $this->getCustomTitle())) , 0, 255);
2890  }
2891  /**
2892  * call after construct
2893  * @return void
2894  */
2895  function postConstructor()
2896  {
2897  }
2898  /**
2899  * no in postUpdate method :: call this only if real change (values)
2900  * @deprecated hook use {@link Doc::postStore} instead
2901  * @see Doc::postStore
2902  * @return string error message
2903  */
2904  function postModify()
2905  {
2906  return "";
2907  }
2908  /**
2909  * no in postUpdate method :: call this only if real change (values)
2910  * @api hook called in ::store()
2911  * @return string error message
2912  */
2913  function postStore()
2914  {
2915  // to be defined in child class
2916  return "";
2917  }
2918  /**
2919  * call in beging store before constraint verification
2920  * if error message is returned store is aborted and the message is returned by store method
2921  * @api hook called in Doc::store()
2922  * @see Doc::store()
2923  * @return string error message
2924  */
2925  function preStore()
2926  {
2927  // to be defined in child class
2928  return "";
2929  }
2930  /**
2931  * called when user edit a document FDL/editcard
2932  * @api hook called when compose edit document web interface
2933  */
2934  function preEdition()
2935  {
2936  // to be defined in child class
2937  return "";
2938  }
2939  /**
2940  * called when user view a document FDL/fdl_card
2941  * @api hook called when compose view document web interface
2942  */
2943  function preConsultation()
2944  {
2945  // to be defined in child class
2946  return "";
2947  }
2948  /**
2949  * call in doc::postInsert method
2950  * @api hook called when document is created in database
2951  * @return string error message
2952  */
2953  function postCreated()
2954  {
2955  // to be defined in child class
2956  return "";
2957  }
2958  /**
2959  * call in doc::add method
2960  * if return message, creation is aborted
2961  * @api hook called before document is created in database
2962  * @return string error message
2963  */
2964  function preCreated()
2965  {
2966  // to be defined in child class
2967  return "";
2968  }
2969  /**
2970  * call when doc is being imported before any modification
2971  * if return non null string import will ne aborted
2972  * @api hook called when import document - before import it
2973  * @param array $extra extra parameters
2974  * @return string error message, if no error empty string
2975  */
2976  function preImport(array $extra = array())
2977  {
2978  return "";
2979  }
2980  /**
2981  * call when doc is imported after databases modification
2982  * the error message will appeared like message
2983  * @api hook called when import document - after it is imported
2984  * @param array $extra extra parameters
2985  * @return string warning message, if no warning empty string
2986  */
2987  function postImport(array $extra = array())
2988  {
2989  return "";
2990  }
2991  /**
2992  * call when doc is being revised before new document is created
2993  * if return non null string revision will ne aborted
2994  * @api hook called when revise document - before revise it
2995  * @see Doc::revise
2996  * @return string error message, if no error empty string
2997  */
2998  function preRevise()
2999  {
3000  return "";
3001  }
3002  /**
3003  * call when doc is revised after new document is created
3004  * the error message will appeared like message
3005  * @api hook called when revise document - after it is revided
3006  * @see Doc::revise
3007  * @return string message - message is added to history
3008  */
3009  function postRevise()
3010  {
3011  return "";
3012  }
3013  /**
3014  * call when doc is being undelete
3015  * if return non null string undelete will ne aborted
3016  * @api hook called before undelete document
3017  * @see Doc::undelete
3018  * @return string error message, if no error empty string
3019  */
3020  function preUndelete()
3021  {
3022  return "";
3023  }
3024  /**
3025  * call when doc is revived after resurrection in database
3026  * the error message will appeared like message
3027  * @api hook called after undelete document
3028  * @return string warning message, if no warning empty string
3029  */
3030  function postUndelete()
3031  {
3032  return "";
3033  }
3034  /**
3035  * call when doc is being undelete
3036  * if return non null string undelete will ne aborted
3037  * @deprecated hook use {@link Doc:::preUndelete} instead
3038  * @see Doc::preUndelete
3039  * @return string error message, if no error empty string
3040  */
3041  function preRevive()
3042  {
3043  return "";
3044  }
3045  /**
3046  * call when doc is revived after resurrection in database
3047  * the error message will appeared like message
3048  * @deprecated hook use {@link Doc:::postUndelete} instead
3049  * @see Doc::postUndelete
3050  * @return string warning message, if no warning empty string
3051  */
3052  function postRevive()
3053  {
3054  return "";
3055  }
3056  /**
3057  * set attribute title value
3058  * the first value of type text use for title will be modify to have the new title
3059  * @param string $title new title
3060  */
3061  final public function setTitle($title)
3062  {
3063  $ltitle = $this->getTitleAttributes();
3064  $otitle = '';
3065  foreach ($ltitle as $at) {
3066  if (($at->type == 'text') && (($at->visibility == 'W') || ($at->visibility == 'O')) && (!$at->inArray())) {
3067  $otitle = $at;
3068  break;
3069  }
3070  }
3071  if ($otitle) {
3072  /*
3073  * @var NormalAttribute $otitle
3074  */
3075  $idt = $otitle->id;
3076 
3077  $this->title = str_replace("\n", " ", $title);
3078  $this->setvalue($idt, $title);
3079  }
3080  }
3081  /**
3082  * return all attribute values
3083  * @return array all attribute values, index is attribute identifier
3084  */
3085  final public function getValues()
3086  {
3087  $lvalues = array();
3088  // if (isset($this->id) && ($this->id>0)) {
3089  $nattr = $this->GetNormalAttributes();
3090  foreach ($nattr as $k => $v) {
3091  $lvalues[$v->id] = $this->getRawValue($v->id);
3092  }
3093  // }
3094  $lvalues = array_merge($lvalues, $this->mvalues); // add more values possibilities
3095  reset($lvalues);
3096  return $lvalues;
3097  }
3098  //-------------------------------------------------------------------
3099 
3100 
3101  /**
3102  * return the raw value (database value) of an attribute document
3103  * @api get the value of an attribute
3104  * @param string $idAttr attribute identifier
3105  * @param string $def default value returned if attribute not found or if is empty
3106  * @code
3107  $doc = new_Doc('',7498 );
3108  if ($doc->isAlive()) {
3109  $rev = $doc->getPropertyValue('revision');
3110  $order = $doc->getRawValue("tst_order");
3111  $level = $doc->getRawValue("tst_level","0");
3112  }
3113  * @endcode
3114  * @see Doc::getAttributeValue
3115  * @return string the attribute value
3116  */
3117  final public function getRawValue($idAttr, $def = "")
3118  {
3119  $lidAttr = strtolower($idAttr);
3120  if (isset($this->$lidAttr) && ($this->$lidAttr != "")) return $this->$lidAttr;
3121 
3122  return $def;
3123  }
3124  /**
3125  * get a typed value of an attribute
3126  *
3127  * return value of an attribute
3128  * return null if value is empty
3129  * return an array for multiple value
3130  * return date in DateTime format, number in int or double
3131  * @api get typed value of an attribute
3132  * @param string $idAttr attribute identifier
3133  * @throws Dcp\Exception DOC0114 code
3134  * @see ErrorCodeDoc::DOC0114
3135  * @return mixed the typed value
3136  */
3137  final public function getAttributeValue($idAttr)
3138  {
3139  /**
3140  * @var \NormalAttribute $oa
3141  */
3142  $oa = $this->getAttribute($idAttr, $nothing, false);
3143  if (!$oa) {
3144  throw new Dcp\Exception('DOC0114', $idAttr, $this->title, $this->fromname);
3145  }
3146 
3147  if (empty($oa->isNormal)) {
3148  throw new Dcp\Exception('DOC0116', $idAttr, $this->title, $this->fromname);
3149  }
3150  return Dcp\AttributeValue::getTypedValue($this, $oa);
3151  }
3152  /**
3153  * Set a value to a document's attribute
3154  * the affectation is only in object. To set modification in database the Doc::store() method must be
3155  * call after modification
3156  * @api Set a value to an attribute
3157  * @param string $idAttr attribute identifier
3158  * @param mixed $value the new value - value format must be compatible with type
3159  * @throws Dcp\Exception
3160  * @see ErrorCodeDoc::DOC0115
3161  * @see ErrorCodeDoc::DOC0117
3162  * @return void
3163  */
3164  final public function setAttributeValue($idAttr, $value)
3165  {
3166  $localRecord = array();
3167  $oa = $this->getAttribute($idAttr);
3168  if (!$oa) {
3169  throw new Dcp\Exception('DOC0115', $idAttr, $this->title, $this->fromname);
3170  }
3171  if (empty($oa->isNormal)) {
3172  throw new Dcp\Exception('DOC0117', $idAttr, $this->title, $this->fromname);
3173  }
3174  /*
3175  * @var NormalAttribute $oa
3176  */
3177  if ($oa->type === "array") {
3178  // record current array values
3179  $ta = $this->attributes->getArrayElements($oa->id);
3180  foreach ($ta as $k => $v) {
3181  $localRecord[$k] = $this->getRawValue($v->id);
3182  }
3183  }
3185  if ($oa->type === "array") {
3186  foreach ($localRecord as $aid => $v) {
3187  if ($this->$aid !== $v) {
3188  $this->_oldvalue[$aid] = $v;
3189  }
3190  }
3191  }
3192  }
3193  /**
3194  * return the value of an attribute document
3195  * @deprecated use {@link Doc::getRawValue} instead
3196  * @param string $idAttr attribute identifier
3197  * @param string $def default value returned if attribute not found or if is empty
3198  * @see Doc::getRawValue
3199  * @return string the attribute value
3200  */
3201  final public function getValue($idAttr, $def = "")
3202  {
3203  static $first = true;
3204  if ($first) {
3206  $first = false;
3207  }
3208  return $this->getRawValue($idAttr, $def);
3209  }
3210  /**
3211  * return all values of a multiple value attribute
3212  *
3213  * the attribute must be in an array or declared with multiple option
3214  * @deprecated use {@link Doc::getMultipleRawValues} instead
3215  * @param string $idAttr identifier of list attribute
3216  * @param string $def default value returned if attribute not found or if is empty
3217  * @param int $index the values for $index row (default value -1 means all values)
3218  * @see Doc::getMultipleRawValues
3219  * @return array the list of attribute values
3220  */
3221  final public function getTValue($idAttr, $def = "", $index = - 1)
3222  {
3223  static $first = true;
3224  if ($first) {
3226  $first = false;
3227  }
3228  return $this->getMultipleRawValues($idAttr, $def, $index);
3229  }
3230  /**
3231  * return all values of a multiple value attribute
3232  *
3233  * @api return all values of a multiple value attribute
3234  * the attribute must be in an array or declared with multiple option
3235  * @param string $idAttr identifier of list attribute
3236  * @param string $def default value returned if attribute not found or if is empty
3237  * @param int $index the values for $index row (default value -1 means all values)
3238  * @return array|string the list of attribute values
3239  */
3240  final public function getMultipleRawValues($idAttr, $def = "", $index = - 1)
3241  {
3242  $v = $this->getRawValue("$idAttr", null);
3243  if ($v === null) {
3244  if ($index == - 1) return array();
3245  else return $def;
3246  } else if ($v == "\t") {
3247  if ($index == - 1) return array(
3248  ""
3249  );
3250  else return $def;
3251  }
3252  $t = $this->rawValueToArray($v);
3253  if ($index == - 1) {
3254  $oa = $this->getAttribute($idAttr, $nothing, false);
3255  if ($oa && $oa->type == "xml") {
3256  foreach ($t as $k => $v) {
3257  $t[$k] = str_replace('<BR>', "\n", $v);
3258  }
3259  }
3260  return $t;
3261  }
3262  if (isset($t[$index])) {
3263  $oa = $this->getAttribute($idAttr, $nothing, false);
3264  if ($oa && $oa->type == "xml") $t[$index] = str_replace('<BR>', "\n", $t[$index]);
3265  return $t[$index];
3266  } else return $def;
3267  }
3268  /**
3269  * return the array of values for an array attribute
3270  *
3271  * the attribute must an array type
3272  * @deprecated use {@link Doc::getArrayRawValues} instead
3273  * @see Doc::getArrayRawValues
3274  * @param string $idAttr identifier of array attribute
3275  * @param int $index the values for $index row (default value -1 means all values)
3276  * @return array all values of array order by rows (return false if not an array attribute)
3277  */
3278  final public function getAValues($idAttr, $index = - 1)
3279  {
3281  return $this->getArrayRawValues($idAttr, $index);
3282  }
3283  /**
3284  * return the array of values for an array attribute
3285  *
3286  * the attribute must an array type
3287  * @api get all values for an array attribute
3288  * @param string $idAttr identifier of array attribute
3289  * @param int $index the values for $index row (default value -1 means all values)
3290  * @return array|false all values of array order by rows (return false if not an array attribute)
3291  */
3292  final public function getArrayRawValues($idAttr, $index = - 1)
3293  {
3294  $a = $this->getAttribute($idAttr);
3295  if ($a->type == "array") {
3296  $ta = $this->attributes->getArrayElements($a->id);
3297  $ti = $tv = array();
3298  $ix = 0;
3299  // transpose
3300  foreach ($ta as $k => $v) {
3301  $tv[$k] = $this->getMultipleRawValues($k);
3302  $ix = max($ix, count($tv[$k]));
3303  }
3304  for ($i = 0; $i < $ix; $i++) {
3305  $ti[$i] = array();
3306  }
3307  foreach ($ta as $k => $v) {
3308  for ($i = 0; $i < $ix; $i++) {
3309  $ti[$i]+= array(
3310  $k => isset($tv[$k][$i]) ? $tv[$k][$i] : ''
3311  );
3312  }
3313  }
3314  if ($index == - 1) return $ti;
3315  else return $ti[$index];
3316  }
3317  return false;
3318  }
3319  /**
3320  * delete a row in an array attribute
3321  *
3322  * the attribute must an array type
3323  * @param string $idAttr identifier of array attribute
3324  * @api delete a row in an array attribute
3325  * @param string $index $index row (first is 0)
3326  * @return string error message, if no error empty string
3327  */
3328  final public function removeArrayRow($idAttr, $index)
3329  {
3330  $a = $this->getAttribute($idAttr);
3331  if ($a->type == "array") {
3332  $ta = $this->attributes->getArrayElements($a->id);
3333  $err = "";
3334  // delete in each columns
3335  foreach ($ta as $k => $v) {
3336  $tv = $this->getMultipleRawValues($k);
3337  unset($tv[$index]);
3338  $tvu = array();
3339  foreach ($tv as $vv) $tvu[] = $vv; // key reorder
3340  $err.= $this->setValue($k, $tvu);
3341  }
3342  return $err;
3343  }
3344  return sprintf(_("%s is not an array attribute") , $idAttr);
3345  }
3346  /**
3347  * in case of array where each column are not the same length
3348  *
3349  * the attribute must an array type
3350  * fill uncomplete column with null values
3351  * @param string $idAttr identifier of array attribute
3352  * @param bool $deleteLastEmptyRows by default empty rows which are in the end are deleted
3353  * @return string error message, if no error empty string
3354  */
3355  final public function completeArrayRow($idAttr, $deleteLastEmptyRows = true)
3356  {
3357  /* Prevent recursive calls of completeArrayRow() by setValue() */
3358  static $calls = array();
3359  if (array_key_exists(strtolower($idAttr) , $calls)) {
3360  return '';
3361  } else {
3362  $calls[strtolower($idAttr) ] = 1;
3363  }
3364 
3365  $err = '';
3366  $a = $this->getAttribute($idAttr);
3367  if ($a->type == "array") {
3368  $ta = $this->attributes->getArrayElements($a->id);
3369 
3370  $max = - 1;
3371  $needRepad = false;
3372  $tValues = array();
3373  foreach ($ta as $k => $v) { // delete empty end values
3374  $tValues[$k] = $this->getMultipleRawValues($k);
3375  if ($deleteLastEmptyRows) {
3376  $c = count($tValues[$k]);
3377  for ($i = $c - 1; $i >= 0; $i--) {
3378  if ($tValues[$k][$i] === '' || $tValues[$k][$i] === null) {
3379  unset($tValues[$k][$i]);
3380  $needRepad = true;
3381  } else break;
3382  }
3383  }
3384  }
3385  foreach ($ta as $k => $v) { // detect uncompleted rows
3386  $c = count($tValues[$k]);
3387  if ($max < 0) $max = $c;
3388  else {
3389  if ($c != $max) $needRepad = true;
3390  if ($max < $c) $max = $c;
3391  }
3392  }
3393  if ($needRepad) {
3394  $oldComplete = $this->_setValueCompleteArray;
3395  $this->_setValueCompleteArray = true;
3396  foreach ($ta as $k => $v) { // fill uncompleted rows
3397  $c = count($tValues[$k]);
3398  if ($c < $max) {
3399  $nt = array_pad($tValues[$k], $max, "");
3400  $err.= $this->setValue($k, $nt);
3401  } else {
3402  $err.= $this->setValue($k, $tValues[$k]);
3403  }
3404  }
3405  $this->_setValueCompleteArray = $oldComplete;
3406  }
3407 
3408  unset($calls[strtolower($idAttr) ]);
3409  return $err;
3410  }
3411 
3412  unset($calls[strtolower($idAttr) ]);
3413  return sprintf(_("%s is not an array attribute") , $idAttr);
3414  }
3415  /**
3416  * add new row in an array attribute
3417  *
3418  * the attribute must be an array type
3419  * @api add new row in an array attribute
3420  * @param string $idAttr identifier of array attribute
3421  * @param array $tv values of each column. Array index must be the attribute identifier
3422  * @param int $index $index row (first is 0) -1 at the end; x means before x row
3423  * @return string error message, if no error empty string
3424  */
3425  final public function addArrayRow($idAttr, $tv, $index = - 1)
3426  {
3427  if (!is_array($tv)) return sprintf('values "%s" must be an array', $tv);
3428  $old_setValueCompleteArrayRow = $this->_setValueNeedCompleteArray;
3429  $this->_setValueNeedCompleteArray = false;
3430 
3431  $tv = array_change_key_case($tv, CASE_LOWER);
3432  $a = $this->getAttribute($idAttr);
3433  if ((!empty($a)) && $a->type == "array") {
3434  $err = $this->completeArrayRow($idAttr, false);
3435  if ($err == "") {
3436  $ta = $this->attributes->getArrayElements($a->id);
3437  $attrOut = array_diff(array_keys($tv) , array_keys($ta));
3438  if ($attrOut) {
3439  $this->_setValueNeedCompleteArray = $old_setValueCompleteArrayRow;
3440  return sprintf(_('attribute "%s" is not a part of array "%s"') , implode(', ', $attrOut) , $idAttr);
3441  }
3442 
3443  $err = "";
3444  // add in each columns
3445  foreach ($ta as $k => $v) {
3446  $k = strtolower($k);
3447  $tnv = $this->getMultipleRawValues($k);
3448  $val = isset($tv[$k]) ? $tv[$k] : '';
3449  if ($index == 0) {
3450  array_unshift($tnv, $val);
3451  } elseif ($index > 0 && $index < count($tnv)) {
3452  $t1 = array_slice($tnv, 0, $index);
3453  $t2 = array_slice($tnv, $index);
3454  $tnv = array_merge($t1, array(
3455  $val
3456  ) , $t2);
3457  } else {
3458  $tnv[] = $val;
3459  }
3460  $err.= $this->setValue($k, $tnv);
3461  }
3462  if ($err == "") {
3463  $err = $this->completeArrayRow($idAttr, false);
3464  }
3465  }
3466  $this->_setValueNeedCompleteArray = $old_setValueCompleteArrayRow;
3467  return $err;
3468  }
3469  $this->_setValueNeedCompleteArray = $old_setValueCompleteArrayRow;
3470  return sprintf(_("%s is not an array attribute") , $idAttr);
3471  }
3472  /**
3473  * delete all attributes values of an array
3474  *
3475  * the attribute must be an array type
3476  * @api delete all attributes values of an array
3477  * @param string $idAttr identifier of array attribute
3478  * @return string error message, if no error empty string
3479  */
3480  final public function clearArrayValues($idAttr)
3481  {
3482  $old_setValueCompleteArrayRow = $this->_setValueNeedCompleteArray;
3483  $this->_setValueNeedCompleteArray = false;
3484 
3485  $a = $this->getAttribute($idAttr);
3486  if ($a->type == "array") {
3487  $ta = $this->attributes->getArrayElements($a->id);
3488  $err = "";
3489  // delete each columns
3490  foreach ($ta as $k => $v) {
3491  $err.= $this->clearValue($k);
3492  }
3493  $this->_setValueNeedCompleteArray = $old_setValueCompleteArrayRow;
3494  return $err;
3495  }
3496  $this->_setValueNeedCompleteArray = $old_setValueCompleteArrayRow;
3497  return sprintf(_("%s is not an array attribute") , $idAttr);
3498  }
3499  /**
3500  * delete all attributes values of an array
3501  *
3502  * the attribute must be an array type
3503  * @param string $idAttr identifier of array attribute
3504  * @deprecated use {@link Doc::clearArrayValues} instead
3505  * @see Doc::clearArrayValues
3506  * @return string error message, if no error empty string
3507  */
3508  final public function deleteArray($idAttr)
3509  {
3511  return $this->clearArrayValues($idAttr);
3512  }
3513  /**
3514  * affect value for $attrid attribute
3515  *
3516  * the affectation is only in object. To set modification in database the store method must be
3517  * call after modification
3518  * If value is empty no modification are set. To reset a value use Doc::clearValue method.
3519  * an array can be use as value for values which are in arrays
3520  * @api affect value for an attribute
3521  * @see Doc::setAttributeValue
3522  * @param string $attrid attribute identifier
3523  * @param string $value new value for the attribute
3524  * @param int $index only for array values affect value in a specific row
3525  * @param int &$kvalue in case of error the index of error (for arrays)
3526  * @return string error message, if no error empty string
3527  */
3528  final public function setValue($attrid, $value, $index = - 1, &$kvalue = null)
3529  {
3530  // control edit before set values
3531  if (!$this->withoutControl) {
3532  if ($this->id > 0) { // no control yet if no effective doc
3533  $err = $this->Control("edit");
3534  if ($err != "") return ($err);
3535  }
3536  }
3537  $attrid = strtolower($attrid);
3538  /*
3539  * @var NormalAttribute $oattr
3540  */
3541  $oattr = $this->GetAttribute($attrid);
3542  if ($index > - 1) { // modify one value in a row
3543  $tval = $this->getMultipleRawValues($attrid);
3544  if (($index + 1) > count($tval)) {
3545  $tval = array_pad($tval, $index + 1, "");
3546  }
3547  $tval[$index] = $value;
3548  $value = $tval;
3549  }
3550  if (is_array($value)) {
3551  if (count($value) == 0) {
3552  $value = DELVALUE;
3553  } elseif ((count($value) == 1) && (first($value) === "" || first($value) === null) && (substr(key($value) , 0, 1) != "s")) {
3554  // special tab for array of one empty cell
3555  $value = "\t";
3556  } else {
3557  if ($oattr && $oattr->repeat && (count($value) == 1) && substr(key($value) , 0, 1) == "s") {
3558  $ov = $this->getMultipleRawValues($attrid);
3559  $rank = intval(substr(key($value) , 1));
3560  if (count($ov) < ($rank - 1)) { // fill array if not set
3561  $start = count($ov);
3562  for ($i = $start; $i < $rank; $i++) {
3563  $ov[$i] = "";
3564  }
3565  }
3566  foreach ($value as $k => $v) {
3567  $ov[substr($k, 1, 1) ] = $v;
3568  }
3569  $value = $ov;
3570  }
3571  /*
3572  * Switch the $br separator from "<BR>" to "\r" for HTML text
3573  * attributes in order to not induce a conflict with legitimate
3574  * "<BR>" tags that might appear in the attribute's HTML content.
3575  */
3576  $value = $this->arrayToRawValue($value, (($oattr && $oattr->type === 'htmltext') ? "\r" : "<BR>"));
3577  }
3578  }
3579  if (($value !== "") && ($value !== null)) {
3580  // change only if different
3581  if ($oattr === false) {
3582  if ($this->id > 0) {
3583  return sprintf(_("attribute %s unknow in document \"%s\" [%s]") , $attrid, $this->getTitle() , $this->fromname);
3584  } else {
3585  return sprintf(_("attribute %s unknow in family \"%s\"") , $attrid, $this->fromname);
3586  }
3587  }
3588  if ($oattr->mvisibility == "I") {
3589  if ($this->_setValueCompleteArray === false) {
3590  return sprintf(_("no permission to modify this attribute %s") , $attrid);
3591  }
3592  }
3593  if ($value === DELVALUE) {
3594  if ($oattr->type != "password") $value = " ";
3595  else return '';
3596  }
3597  if ($value === " ") {
3598  $value = ""; // erase value
3599  if ((!empty($this->$attrid)) || (isset($this->$attrid) && $this->$attrid === "0")) {
3600  //print "change by delete $attrid <BR>\n";
3601  if ($this->_setValueCompleteArray === false) {
3602  $this->hasChanged = true;
3603  $this->_oldvalue[$attrid] = $this->$attrid;
3604  }
3605  $this->$attrid = $value;
3606  if ($oattr->type == "file") {
3607  // need clear computed column
3608  $this->clearFullAttr($oattr->id);
3609  }
3610  }
3611  } else {
3612  $value = trim($value, " \x0B\r"); // suppress white spaces end & begin
3613  if (!isset($this->$attrid)) $this->$attrid = "";
3614 
3615  if (strcmp($this->$attrid, $value) != 0 && strcmp($this->$attrid, str_replace("\n ", "\n", $value)) != 0) {
3616  // print "change2 $attrid to <PRE>[{$this->$attrid}] [$value]</PRE><BR>";
3617  if ($oattr->repeat) {
3618  $tvalues = $this->rawValueToArray($value);
3619  } else {
3620  $tvalues[] = $value;
3621  }
3622 
3623  foreach ($tvalues as $kvalue => $avalue) {
3624  if (($avalue != "") && ($avalue != "\t")) {
3625  if ($oattr) {
3626  $avalue = trim($avalue);
3627  $tvalues[$kvalue] = $avalue;
3628  switch ($oattr->type) {
3629  case 'account':
3630  case 'docid':
3631  $tvalues[$kvalue] = $this->resolveDocIdLogicalNames($oattr, $avalue);
3632  break;
3633 
3634  case 'enum':
3635  if ($oattr->getOption("etype") == "open") {
3636  // added new
3637  $tenum = $oattr->getEnum();
3638  $keys = array_keys($tenum);
3639  if (!in_array($avalue, $keys)) {
3640  $oattr->addEnum($this->dbaccess, $avalue, $avalue);
3641  }
3642  }
3643  break;
3644 
3645  case 'double':
3646  if ($avalue == '-') {
3647  $avalue = 0;
3648  }
3649  $tvalues[$kvalue] = str_replace(",", ".", $avalue);
3650  $tvalues[$kvalue] = str_replace(" ", "", $tvalues[$kvalue]);
3651  if ($avalue != "\t") {
3652  if (!is_numeric($tvalues[$kvalue])) {
3653  return sprintf(_("value [%s] is not a number") , $tvalues[$kvalue]);
3654  } else {
3655  $tvalues[$kvalue] = (string)((double)$tvalues[$kvalue]); // delete non signifiant zeros
3656 
3657  }
3658  }
3659 
3660  break;
3661 
3662  case 'money':
3663  if ($avalue == '-') {
3664  $avalue = 0;
3665  }
3666  $tvalues[$kvalue] = str_replace(",", ".", $avalue);
3667  $tvalues[$kvalue] = str_replace(" ", "", $tvalues[$kvalue]);
3668  if (($avalue != "\t") && (!is_numeric($tvalues[$kvalue]))) {
3669  return sprintf(_("value [%s] is not a number") , $tvalues[$kvalue]);
3670  }
3671  $tvalues[$kvalue] = round(doubleval($tvalues[$kvalue]) , 2);
3672  break;
3673 
3674  case 'integer':
3675  case 'int':
3676  if ($avalue == '-') {
3677  $avalue = 0;
3678  }
3679  if (($avalue != "\t") && (!is_numeric($avalue))) {
3680  return sprintf(_("value [%s] is not a number") , $avalue);
3681  }
3682  if (floatval($avalue) < - floatval(pow(2, 31)) || floatval($avalue) > floatval(pow(2, 31) - 1)) {
3683  // signed int32 overflow
3684  return sprintf(_("[%s] must be between %s and %s") , $avalue, -floatval(pow(2, 31)) , floatval(pow(2, 31) - 1));
3685  }
3686  if (intval($avalue) != floatval($avalue)) {
3687  return sprintf(_("[%s] must be a integer") , $avalue);
3688  }
3689 
3690  $tvalues[$kvalue] = intval($avalue);
3691  break;
3692 
3693  case 'time':
3694  if (preg_match('/^(\d\d?):(\d\d?):?(\d\d?)?$/', $avalue, $reg)) {
3695  $hh = intval($reg[1]);
3696  $mm = intval($reg[2]);
3697  $ss = isset($reg[3]) ? intval($reg[3]) : 0; // seconds are optionals
3698  if ($hh < 0 || $hh > 23 || $mm < 0 || $mm > 59 || $ss < 0 || $ss > 59) {
3699  return sprintf(_("value [%s] is out of limit time") , $avalue);
3700  }
3701  if (isset($reg[3])) {
3702  $tvalues[$kvalue] = sprintf("%02d:%02d:%02d", $hh, $mm, $ss);
3703  } else {
3704  $tvalues[$kvalue] = sprintf("%02d:%02d", $hh, $mm);
3705  }
3706  } else {
3707  return sprintf(_("value [%s] is not a valid time") , $avalue);
3708  }
3709 
3710  break;
3711 
3712  case 'date':
3713  if (trim($avalue) == "") {
3714  if (!$oattr->repeat) {
3715  $tvalues[$kvalue] = "";
3716  }
3717  } else {
3718  if (!isValidDate($avalue)) {
3719  return sprintf(_("value [%s] is not a valid date") , $avalue);
3720  }
3721 
3722  $localeconfig = getLocaleConfig();
3723  if ($localeconfig !== false) {
3724  $tvalues[$kvalue] = stringDateToIso($avalue, $localeconfig['dateFormat']);
3725  } else {
3726  return sprintf(_("local config for date not found"));
3727  }
3728  }
3729  break;
3730 
3731  case 'timestamp':
3732  if (trim($avalue) == "") {
3733  if (!$oattr->repeat) {
3734  $tvalues[$kvalue] = "";
3735  }
3736  } else {
3737  if (!isValidDate($avalue)) {
3738  return sprintf(_("value [%s] is not a valid timestamp") , $avalue);
3739  }
3740 
3741  $localeconfig = getLocaleConfig();
3742  if ($localeconfig !== false) {
3743  $tvalues[$kvalue] = stringDateToIso($avalue, $localeconfig['dateTimeFormat']);
3744  } else {
3745  return sprintf(_("local config for timestamp not found"));
3746  }
3747  }
3748  break;
3749 
3750  case 'file':
3751  // clear fulltext realtive column
3752  if ((!$oattr->repeat) || ($avalue != $this->getMultipleRawValues($attrid, "", $kvalue))) {
3753  // only if changed
3754  $this->clearFullAttr($oattr->id, ($oattr->repeat) ? $kvalue : -1);
3755  }
3756  $tvalues[$kvalue] = str_replace('\\', '', $tvalues[$kvalue]); // correct possible save error in old versions
3757  break;
3758 
3759  case 'image':
3760  $tvalues[$kvalue] = str_replace('\\', '', $tvalues[$kvalue]);
3761  break;
3762 
3763  case 'htmltext':
3764  $tvalues[$kvalue] = str_replace('&#39;', "'", $tvalues[$kvalue]);
3765  $tvalues[$kvalue] = preg_replace("/<!--.*?-->/ms", "", $tvalues[$kvalue]); //delete comments
3766  $tvalues[$kvalue] = \Dcp\Utils\htmlclean::xssClean($tvalues[$kvalue]);
3767  if ($oattr->getOption("htmlclean") == "yes") {
3768  $tvalues[$kvalue] = \Dcp\Utils\htmlclean::cleanStyle($tvalues[$kvalue]);
3769  }
3770  /* Check for malformed HTML */
3771  $html = \Dcp\Utils\htmlclean::normalizeHTMLFragment($tvalues[$kvalue], $error);
3772  if ($html === false) {
3773  $html = '';
3774  }
3775  /* Return error on malformed HTML */
3776  if ($error != '') {
3777  return _("Malformed HTML:") . "\n" . $error;
3778  }
3779  /* If htmlclean is set, then use the normalized HTML fragment instead */
3780  if ($oattr->getOption("htmlclean") == "yes") {
3781  $tvalues[$kvalue] = $html;
3782  }
3783  /* Encode '[' to prevent further layout interpretation/evaluation */
3784  $tvalues[$kvalue] = str_replace("[", "&#x5B;", $tvalues[$kvalue]); // need to stop auto instance
3785  break;
3786 
3787  case 'thesaurus':
3788  // reset cache of doccount
3789  include_once ("FDL/Class.DocCount.php");
3790  $d = new docCount($this->dbaccess);
3791  $d->famid = $this->fromid;
3792  $d->aid = $attrid;
3793  $d->deleteAll();
3794  break;
3795 
3796  case 'text':
3797  $tvalues[$kvalue] = str_replace("\r", " ", $tvalues[$kvalue]);
3798  break;
3799  }
3800  }
3801  }
3802  }
3803  //print "<br/>change $attrid to :".$this->$attrid."->".implode("\n",$tvalues);
3804  $rawValue = implode("\n", $tvalues);
3805  if (!$this->_setValueCompleteArray && $this->$attrid != $rawValue) {
3806  $this->_oldvalue[$attrid] = $this->$attrid;
3807  $this->hasChanged = true;
3808  }
3809  $this->$attrid = $rawValue;
3810  }
3811  }
3812  }
3813  if ($this->_setValueNeedCompleteArray && $oattr && $oattr->inArray()) {
3814  return $this->completeArrayRow($oattr->fieldSet->id);
3815  }
3816  return '';
3817  }
3818  /**
3819  * clear $attrid_txt and $attrid_vec
3820  *
3821  * @param string $attrid identifier of file attribute
3822  * @param int $index in case of multiple values
3823  * @return void
3824  */
3825  final private function clearFullAttr($attrid, $index = - 1)
3826  {
3827  $attrid = strtolower($attrid);
3828  $oa = $this->getAttribute($attrid);
3829  if ($oa && $oa->usefor != 'Q') {
3830  if ($oa->getOption("search") != "no") {
3831  $ak = $attrid . '_txt';
3832  if ($index == - 1) {
3833  $this->$ak = '';
3834  } else {
3835  if ($this->affectColumn(array(
3836  $ak
3837  ) , false)) {
3838  $this->$ak = sep_replace($this->$ak, $index);
3839  }
3840  }
3841  $this->fields[$ak] = $ak;
3842  $ak = $attrid . '_vec';
3843  $this->$ak = '';
3844  $this->fields[$ak] = $ak;
3845  $this->fulltext = '';
3846  $this->fields['fulltext'] = 'fulltext'; // to enable trigger
3847  $this->textsend[$attrid . $index] = array(
3848  "attrid" => $attrid,
3849  "index" => $index
3850  );
3851  }
3852  }
3853  }
3854  /**
3855  * send text transformation
3856  * after ::clearFullAttr is called
3857  *
3858  */
3859  final private function sendTextToEngine()
3860  {
3861  $err = '';
3862  if (!empty($this->textsend)) {
3863  include_once ("FDL/Lib.Vault.php");
3864  foreach ($this->textsend as $k => $v) {
3865  $index = $v["index"];
3866  if ($index > 0) $fval = $this->getMultipleRawValues($v["attrid"], "", $index);
3867  else $fval = strtok($this->getRawValue($v["attrid"]) , "\n");
3868  if (preg_match(PREGEXPFILE, $fval, $reg)) {
3869  $vid = $reg[2];
3870  if (isset($this->vidNoSendTextToEngine[$vid])) {
3871  return '';
3872  }
3873  $err = sendTextTransformation($this->dbaccess, $this->id, $v["attrid"], $index, $vid);
3874  if ($err != "") {
3875  $this->addHistoryEntry(_("error sending text conversion") . ": $err", DocHisto::NOTICE);
3876  }
3877  $this->vidNoSendTextToEngine[$vid] = true;
3878  }
3879  }
3880  $this->textsend = array(); //reinit
3881 
3882  }
3883  return $err;
3884  }
3885  /**
3886  * force recompute all file text transformation
3887  * @param string $aid file attribute identifier. If empty all files attributes will be reseted
3888  * @return string error message, if no error empty string
3889  */
3890  final public function recomputeTextFiles($aid = '')
3891  {
3892  if (!$aid) $afiles = $this->GetFileAttributes(true);
3893  else $afiles[$aid] = $this->getAttribute($aid);
3894 
3895  $ttxt = array();
3896  foreach ($afiles as $k => $v) {
3897  $kt = $k . '_txt';
3898  $ttxt[] = $kt;
3899  if ($v->inArray()) {
3900  $tv = $this->getMultipleRawValues($k);
3901  foreach ($tv as $kv => $vv) {
3902  $this->clearFullAttr($k, $kv);
3903  }
3904  } else {
3905  $this->clearFullAttr($k);
3906  }
3907  $this->$kt = '';
3908  $kv = $k . '_vec';
3909  $ttxt[] = $kv;
3910  $this->$kv = '';
3911  }
3912  $this->modify(true, $ttxt, true);
3913  $err = $this->sendTextToEngine();
3914  return $err;
3915  }
3916  /**
3917  * affect text value in $attrid file attribute
3918  *
3919  * create a new file in Vault to replace old file
3920  * @param string $attrid identifier of file attribute
3921  * @param string $value new value for the attribute
3922  * @param string $ftitle the name of file (if empty the same as before)
3923  * @return string error message, if no error empty string
3924  */
3925  final public function setTextValueInFile($attrid, $value, $ftitle = "")
3926  {
3927  $err = '';
3928  $a = $this->getAttribute($attrid);
3929  if ($a->type == "file") {
3930  $vf = newFreeVaultFile($this->dbaccess);
3931  $fvalue = $this->getRawValue($attrid);
3932  $basename = "";
3933  if (preg_match(PREGEXPFILE, $fvalue, $reg)) {
3934  $vaultid = $reg[2];
3935  //$mimetype = $reg[1];
3936  $info = new vaultFileInfo();
3937  $err = $vf->Retrieve($vaultid, $info);
3938 
3939  if ($err == "") {
3940  $basename = $info->name;
3941  }
3942  }
3943  $filename = uniqid(getTmpDir() . "/_html") . ".html";
3944  $nc = file_put_contents($filename, $value);
3945  /*
3946  * @var int $vid
3947  */
3948  $err = $vf->Store($filename, false, $vid);
3949  if ($ftitle != "") {
3950  $vf->Rename($vid, $ftitle);
3951  $basename = $ftitle;
3952  } else {
3953  if ($basename != "") { // keep same file name
3954  $vf->Rename($vid, $basename);
3955  }
3956  }
3957  if ($err == "") {
3958  $mime = trim(shell_exec(sprintf("file -ib %s", escapeshellarg($filename))));
3959  $value = "$mime|$vid|$basename";
3960  $err = $this->setValue($attrid, $value);
3961  //$err="file conversion $mime|$vid";
3962  if ($err == "xx") {
3963  $this->clearFullAttr($attrid); // because internal values not changed
3964 
3965  }
3966  }
3967  if ($nc > 0) unlink($filename);
3968  }
3969  return $err;
3970  }
3971  /**
3972  * get text value from $attrid file attribute
3973  *
3974  * get content of a file (must be an ascii file)
3975  * @param string $attrid identifier of file attribute
3976  * @param string &$text the content of the file
3977  * @return string error message, if no error empty string
3978  */
3979  final public function getTextValueFromFile($attrid, &$text)
3980  {
3981  $err = '';
3982  $a = $this->getAttribute($attrid);
3983  if ($a->type == "file") {
3984  $vf = newFreeVaultFile($this->dbaccess);
3985  $fvalue = $this->getRawValue($attrid);
3986  if (preg_match(PREGEXPFILE, $fvalue, $reg)) {
3987  $vaultid = $reg[2];
3988  $info = new VaultFileInfo();
3989  /**
3990  * VaultFileInfo $info
3991  */
3992  $err = $vf->Retrieve($vaultid, $info);
3993 
3994  if (!$err) {
3995  $filename = $info->path;
3996  $text = file_get_contents($filename);
3997  }
3998  }
3999  }
4000  return $err;
4001  }
4002  /**
4003  * save stream file in an file attribute
4004  *
4005  * replace a new file in Vault to replace old file
4006  * @param string $attrid identifier of file attribute
4007  * @param resource $stream file resource from fopen
4008  * @param string $ftitle to change title of file also (empty to unchange)
4009  * @param int $index for array of file : modify in specific row
4010  * @return string error message, if no error empty string
4011  */
4012  final public function saveFile($attrid, $stream, $ftitle = "", $index = - 1)
4013  {
4014  $err = '';
4015  if (is_resource($stream) && get_resource_type($stream) == "stream") {
4016  $mimetype = $ext = $oftitle = $vaultid = '';
4017  $a = $this->getAttribute($attrid);
4018  if ($a->type == "file") {
4019  $vf = newFreeVaultFile($this->dbaccess);
4020  if ($index > - 1) $fvalue = $this->getMultipleRawValues($attrid, '', $index);
4021  else $fvalue = $this->getRawValue($attrid);
4022  $basename = "";
4023  if (preg_match(PREGEXPFILE, $fvalue, $reg)) {
4024  $vaultid = $reg[2];
4025  $mimetype = $reg[1];
4026  $oftitle = $reg[3];
4027  $info = new VaultFileInfo();
4028  $err = $vf->Retrieve($vaultid, $info);
4029 
4030  if ($err == "") {
4031  $basename = $info->name;
4032  }
4033  }
4034  if ($ftitle) {
4035  $ext = getFileExtension($ftitle);
4036  }
4037  if ($ext == "") $ext = "nop";
4038 
4039  $filename = uniqid(getTmpDir() . "/_fdl") . ".$ext";
4040  $tmpstream = fopen($filename, "w");
4041  while (!feof($stream)) {
4042  if (false === fwrite($tmpstream, fread($stream, 4096))) {
4043  $err = "403 Forbidden";
4044  break;
4045  }
4046  }
4047  fclose($tmpstream);
4048  if (!$err) {
4049  // verify if need to create new file in case of revision
4050  $newfile = ($basename == "");
4051 
4052  if ($this->revision > 0) {
4053  $trev = $this->GetRevisions("TABLE", 2);
4054  /**
4055  * @var $revdoc array
4056  */
4057  $revdoc = $trev[1];
4058  $prevfile = getv($revdoc, strtolower($attrid));
4059  if ($prevfile == $fvalue) $newfile = true;
4060  }
4061 
4062  if (!$newfile) {
4063  $err = $vf->Save($filename, false, $vaultid);
4064  } else {
4065  $err = $vf->Store($filename, false, $vaultid);
4066  }
4067  if ($ftitle != "") {
4068  $vf->Rename($vaultid, $ftitle);
4069  } elseif ($basename != "") { // keep same file name
4070  $vf->Rename($vaultid, $basename);
4071  }
4072  if ($err == "") {
4073  if ($mimetype) $mime = $mimetype;
4074  else $mime = trim(shell_exec(sprintf("file -ib %s", escapeshellarg($filename))));
4075  if ($ftitle) $value = "$mime|$vaultid|$ftitle";
4076  else $value = "$mime|$vaultid|$oftitle";
4077  $err = $this->setValue($attrid, $value, $index);
4078  if ($err == "") {
4079  $this->clearFullAttr($attrid); // because internal values not changed
4080 
4081  }
4082  //$err="file conversion $mime|$vid";
4083 
4084  }
4085  unlink($filename);
4086  $this->addHistoryEntry(sprintf(_("modify file %s") , $ftitle));
4087  $this->hasChanged = true;
4088  }
4089  }
4090  }
4091  return $err;
4092  }
4093  /**
4094  * use for duplicate physicaly the file
4095  *
4096  * @param string $idattr identifier of file attribute
4097  * @param string $newname basename if want change name of file
4098  * @param int $index in case of array
4099  * @return string attribut value formated to be inserted into a file attribute
4100  */
4101  final function copyFile($idattr, $newname = "", $index = - 1)
4102  {
4103  if ($index >= 0) $f = $this->getMultipleRawValues($idattr, "", $index);
4104  else $f = $this->getRawValue($idattr);
4105  if ($f) {
4106  if (preg_match(PREGEXPFILE, $f, $reg)) {
4107  $vf = newFreeVaultFile($this->dbaccess);
4108  /*
4109  * @var vaultFileInfo $info
4110  */
4111  if ($vf->Show($reg[2], $info) == "") {
4112  $cible = $info->path;
4113  if (file_exists($cible)) {
4114  /*
4115  * @var int $vid vault id
4116  */
4117  $err = $vf->Store($cible, false, $vid);
4118  if ($err == "") {
4119  if (!$newname) $newname = $info->name;
4120  if ($newname) {
4121  $vf->Rename($vid, $newname);
4122  }
4123  return $reg[1] . "|$vid|$newname";
4124  }
4125  }
4126  }
4127  }
4128  }
4129  return false;
4130  }
4131  /**
4132  * rename physicaly the file
4133  *
4134  * @param string $idattr identifier of file attribute
4135  * @param string $newname base name file
4136  * @param int $index in case of array of files
4137  * @return string empty if no error
4138  */
4139  final function renameFile($idattr, $newname, $index = - 1)
4140  {
4141  if ($newname) {
4142  if ($index == - 1) $f = $this->getRawValue($idattr);
4143  else $f = $this->getMultipleRawValues($idattr, "", $index);
4144  if ($f) {
4145  if (preg_match(PREGEXPFILE, $f, $reg)) {
4146  $vf = newFreeVaultFile($this->dbaccess);
4147  $vid = $reg[2];
4148  /*
4149  * @var vaultFileInfo $info
4150  */
4151  if ($vf->Show($reg[2], $info) == "") {
4152  $cible = $info->path;
4153  if (file_exists($cible)) {
4154 
4155  $vf->Rename($vid, $newname);
4156  $this->setValue($idattr, $info->mime_s . '|' . $vid . '|' . $newname, $index);
4157  }
4158  }
4159  }
4160  }
4161  }
4162  return false;
4163  }
4164  /**
4165  * Register (store) a file in the vault and return the file's vault's informations
4166  *
4167  * @param string $filename the file pathname
4168  * @param string $ftitle override the stored file name or empty string to keep the original file name
4169  * @param VaultFileInfo $info the vault's informations for the stored file or null if could not get informations
4170  * @return string trigram of the file in the vault: "mime_s|id_file|name"
4171  * @throws \Exception on error
4172  */
4173  final public function vaultRegisterFile($filename, $ftitle = "", &$info = null)
4174  {
4175  include_once ('FDL/Lib.Vault.php');
4176 
4177  $vaultid = 0;
4178  $err = vault_store($filename, $vaultid, $ftitle);
4179  if ($err != '') {
4180  throw new \Exception(ErrorCode::getError('FILE0009', $filename, $err));
4181  }
4183  if (!is_object($info) || !is_a($info, 'VaultFileInfo')) {
4184  throw new \Exception(ErrorCode::getError('FILE0010', $filename));
4185  }
4186 
4187  return sprintf("%s|%s|%s", $info->mime_s, $info->id_file, $info->name);
4188  }
4189  /**
4190  * Store a file in a file attribute
4191  *
4192  * @param string $attrid identifier of file attribute
4193  * @param string $filename file path
4194  * @param string $ftitle basename of file
4195  * @param int $index only for array values affect value in a specific row
4196  * @return string error message, if no error empty string
4197  */
4198  final public function setFile($attrid, $filename, $ftitle = "", $index = - 1)
4199  {
4200  include_once ("FDL/Lib.Vault.php");
4201 
4202  try {
4203  $a = $this->getAttribute($attrid);
4204  if ($a) {
4205  if (($a->type == "file") || ($a->type == "image")) {
4206  $info = null;
4207  $vaultid = $this->vaultRegisterFile($filename, $ftitle, $info);
4208  $err = $this->setValue($attrid, $vaultid, $index);
4209  } else {
4210  $err = sprintf(_("attribute %s is not a file attribute") , $a->getLabel());
4211  }
4212  } else {
4213  $err = sprintf(_("unknow attribute %s") , $attrid);
4214  }
4215  }
4216  catch(\Exception $e) {
4217  errorLogException($e);
4218  $err = $e->getMessage();
4219  }
4220  return $err;
4221  }
4222  /**
4223  * store new file in an file attribute
4224  *
4225  * @deprecated use setFile() instead
4226  *
4227  * @param string $attrid identifier of file attribute
4228  * @param string $filename file path
4229  * @param string $ftitle basename of file
4230  * @param int $index only for array values affect value in a specific row
4231  * @return string error message, if no error empty string
4232  */
4233  final public function storeFile($attrid, $filename, $ftitle = "", $index = - 1)
4234  {
4236 
4237  return $this->setFile($attrid, $filename, $ftitle, $index);
4238  }
4239  /**
4240  * store multiples new files in an file array attribute
4241  *
4242  * @deprecated use setFile() instead
4243  *
4244  * @param string $attrid identifier of file attribute
4245  * @param array $filenames file path
4246  * @param array|string $ftitle basename of file
4247  * @return string error message, if no error empty string
4248  */
4249  final public function storeFiles($attrid, $filenames, $ftitle = "")
4250  {
4252  $err = '';
4253  if (!is_array($filenames)) return _("no files");
4254 
4255  $a = $this->getAttribute($attrid);
4256  if (($a->type == "file") || ($a->type == "image")) {
4257  if ($a->inArray()) {
4258  $tvid = array();
4259  foreach ($filenames as $k => $filename) {
4260  if (is_file($filename)) {
4261  include_once ("FDL/Lib.Vault.php");
4262 
4263  $err = vault_store($filename, $vaultid, $ftitle[$k]);
4264  if ($err == "") {
4266  $mime = $info->mime_s;
4267  if ($ftitle[$k] == "") $ftitle[$k] = $info->name;
4268  $tvid[] = "$mime|$vaultid|" . $ftitle[$k];
4269  }
4270  }
4271  }
4272  $this->setValue($attrid, $tvid);
4273  } else {
4274  $err = sprintf(_("attribute %s is not int a array") , $a->getLabel());
4275  }
4276  } else {
4277  $err = sprintf(_("attribute %s is not a file attribute") , $a->getLabel());
4278  }
4279 
4280  return $err;
4281  }
4282  /**
4283  * Duplicate physically all files of documents
4284  *
4285  */
4286  function duplicateFiles()
4287  {
4288  $err = "";
4289  $fa = $this->GetFileAttributes();
4290  foreach ($fa as $aid => $oa) {
4291  if ($oa->inArray()) {
4292  $t = $this->getMultipleRawValues($oa->id);
4293  $tcopy = array();
4294  foreach ($t as $k => $v) {
4295  $tcopy[$k] = $this->copyFile($oa->id, "", $k);
4296  }
4297  $this->setValue($oa->id, $tcopy);
4298  } else {
4299  $this->setValue($oa->id, $this->copyFile($oa->id));
4300  }
4301  }
4302  return $err;
4303  }
4304  /**
4305  * Return the related value by linked attributes.
4306  *
4307  * Can be used to retrieve a value by traversing multiple docid.
4308  *
4309  * For example,
4310  * @code
4311  * $val = $this->getRValue("id1:id2:id3")
4312  * @endcode
4313  * is a shortcut for
4314  * @code
4315  * $id1 = $this->getRawValue("id1");
4316  * $doc1 = new_Doc('', $id1);
4317  * $id2 = $doc1->getRawValue("id2");
4318  * $doc2 = new_Doc('', $id2);
4319  * $val = $doc2->getRawValue('', "id3");
4320  * @endcode
4321  *
4322  * @warning
4323  * Each of the traversed docid **must** be a docid or an account, and **must not** be multiple.\n
4324  * Elsewhere, the returned value is $def
4325  * @endwarning
4326  *
4327  * @param string $RidAttr attributes identifier chain (separated by ':')
4328  * @param string $def $def default return value
4329  * @param bool $latest always last revision of document
4330  * @param bool $html return formated value for html
4331  * @return array|string
4332  */
4333  final public function getRValue($RidAttr, $def = "", $latest = true, $html = false)
4334  {
4335  $tattrid = explode(":", $RidAttr);
4336  $lattrid = array_pop($tattrid); // last attribute
4337  $doc = $this;
4338  foreach ($tattrid as $k => $v) {
4339  $docid = $doc->getRawValue($v);
4340  if ($docid == "") return $def;
4341  $doc = new_Doc($this->dbaccess, $docid);
4342 
4343  if ($latest) {
4344  if ($doc->locked == - 1) { // it is revised document
4345  $ldocid = $doc->getLatestId();
4346  if ($ldocid != $doc->id) $doc = new_Doc($this->dbaccess, $ldocid);
4347  }
4348  }
4349  if (!$doc->isAlive()) return $def;
4350  }
4351  if ($html) return $doc->getHtmlAttrValue($lattrid, $def);
4352  else return $doc->getRawValue($lattrid, $def);
4353  }
4354  /**
4355  * return the previous value for a attibute set before Doc::SetValue
4356  * can be used in Doc::postStore generaly
4357  * @deprecated use Doc::getOldRawvalue
4358  * @see Doc::getOldRawValue
4359  * @param string $attrid attribute identifier
4360  * @return string the old value (false if not modified before)
4361  */
4362  final public function getOldValue($attrid)
4363  {
4365  return $this->getOldRawValue($attrid);
4366  }
4367  /**
4368  * return the previous value for a attibute set before Doc::SetValue
4369  * can be used in Doc::postModify generaly
4370  * @api get previous value of an attribute
4371  * @param string $attrid attribute identifier
4372  * @return string the old value (false if not modified before)
4373  *
4374  */
4375  final public function getOldRawValue($attrid)
4376  {
4377  $attrid = strtolower($attrid);
4378  if (isset($this->_oldvalue[$attrid])) return $this->_oldvalue[$attrid];
4379  return false;
4380  }
4381  /**
4382  * return all modified values from last modify
4383  * @deprecated use Doc::getOldRawValues instead
4384  * @see Doc::getOldRawValues
4385  * @return array indexed by attribute identifier (lowercase)
4386  */
4387  final public function getOldValues()
4388  {
4390  return $this->getOldRawValues();
4391  }
4392  /**
4393  * return all modified values from last modify
4394  * @api get all modified values from last modify
4395  * @return array indexed by attribute identifier (lowercase)
4396  */
4397  final public function getOldRawValues()
4398  {
4399  if (isset($this->_oldvalue)) return $this->_oldvalue;
4400  return array();
4401  }
4402  /**
4403  * delete a value of an attribute
4404  * @see Doc::setValue
4405  * @param string $attrid attribute identifier
4406  * @api clear value of an attribute
4407  * @return string error message
4408  */
4409  final public function clearValue($attrid)
4410  {
4411  $oattr = $this->GetAttribute($attrid);
4412  if ($oattr->type == 'docid') {
4413  $doctitle = $oattr->getOption('doctitle');
4414  if ($doctitle == 'auto') {
4415  $doctitle = $attrid . '_title';
4416  }
4417  if (!empty($doctitle)) {
4418  $this->SetValue($doctitle, " ");
4419  }
4420  }
4421  return $this->SetValue($attrid, " ");
4422  }
4423  /**
4424  * delete a value of an attribute
4425  * @see Doc::setValue
4426  * @param string $attrid attribute identifier
4427  * @deprecated use {@link Doc::clearValue} instead
4428  * @see Doc::clearValue
4429  * @return string error message
4430  */
4431  final public function deleteValue($attrid)
4432  {
4434  return $this->clearValue($attrid);
4435  }
4436  /**
4437  * add values present in values field
4438  */
4439  private function getMoreValues()
4440  {
4441  if (isset($this->values)) {
4442  $tvalues = explode("£", $this->values);
4443  $tattrids = explode("£", $this->attrids);
4444  if (count($tvalues) === count($tattrids)) {
4445  foreach ($tvalues as $k => $v) {
4446  $attrid = $tattrids[$k];
4447  if (($attrid != "") && empty($this->$attrid)) {
4448  $this->$attrid = $v;
4449  $this->mvalues[$attrid] = $v; // to be use in getValues()
4450 
4451  }
4452  }
4453  } else {
4454  // Special case when £ characters is used in value
4455  $missingAttrIds = array();
4456  foreach ($tattrids as $k => $attrid) {
4457  if ($attrid && $this->$attrid === null) {
4458  $missingAttrIds[] = $attrid;
4459  }
4460  }
4461  if ($missingAttrIds) {
4462  $missingValues = getTDoc($this->dbaccess, $this->id, array() , $missingAttrIds);
4463  foreach ($missingValues as $attrid => $value) {
4464  $this->$attrid = $value;
4465  }
4466  }
4467  }
4468  }
4469  }
4470  /**
4471  * reset values present in values field
4472  */
4473  private function resetMoreValues()
4474  {
4475  if (isset($this->values) && $this->id) {
4476  $tattrids = explode("£", $this->attrids);
4477  foreach ($tattrids as $k => $v) {
4478  if ($v) {
4479  $this->$v = null;
4480  }
4481  }
4482  }
4483  $this->mvalues = array();
4484  }
4485  /**
4486  * @param $value
4487  * @return string
4488  */
4489  final public function getValueMethod($value)
4490  {
4491  $value = $this->ApplyMethod($value, $value);
4492  return $value;
4493  }
4494 
4495  public static function seemsMethod($method)
4496  {
4497  return is_string($method) && preg_match('/([^:]*)::([^\(]+)\(([^\)]*)\)/', $method);
4498  }
4499  /**
4500  * apply a method to a doc
4501  * specified like ::getFoo(10)
4502  * @param string $method the method to apply
4503  * @param string $def default value if no method
4504  * @param int $index index in case of value in row
4505  * @param array $bargs first arguments sent before for the method
4506  * @param array $mapArgs indexed array to add more possibilities to map arguments
4507  * @param string $err error message
4508  *
4509  * @return string the value
4510  */
4511  final public function applyMethod($method, $def = "", $index = - 1, array $bargs = array() , array $mapArgs = array() , &$err = '')
4512  {
4513  $value = $def;
4514  $err = '';
4515 
4516  if (self::seemsMethod($method)) {
4517 
4518  $parseMethod = new parseFamilyMethod();
4519  $parseMethod->parse($method);
4520  $err = $parseMethod->getError();
4521  if ($err) return $err;
4522 
4523  $staticClass = $parseMethod->className;
4524  if (!$staticClass) $staticClass = $this;
4525  $methodName = $parseMethod->methodName;
4526  if (method_exists($staticClass, $methodName)) {
4527  if ((count($parseMethod->inputs) == 0) && (empty($bargs))) {
4528  // without argument
4529  $value = call_user_func(array(
4530  $staticClass,
4531  $methodName
4532  ));
4533  } else {
4534  // with argument
4535  $args = array();
4536 
4537  $inputs = array();
4538  foreach ($bargs as $extraArg) {
4539  $inputs[] = new inputArgument($extraArg);
4540  }
4541  $inputs = array_merge($inputs, $parseMethod->inputs);
4542  foreach ($inputs as $ki => $input) {
4543  $args[$ki] = null;
4544  if ($input->type == "string") {
4545  $args[$ki] = $input->name;
4546  } else {
4547  $mapped = (isset($mapArgs[strtolower($input->name) ])) ? $mapArgs[strtolower($input->name) ] : null;
4548  if ($mapped) {
4549  if (is_object($mapped)) $args[$ki] = & $mapArgs[strtolower($input->name) ];
4550  else $args[$ki] = $mapped;
4551  } elseif ($attr = $this->getAttribute($input->name)) {
4552  if ($attr->usefor == 'Q') {
4553  if ($attr->inArray()) {
4554  $pas = $this->rawValueToArray($this->getFamilyParameterValue($input->name));
4555  if ($index == - 1) $args[$ki] = $pas;
4556  else $args[$ki] = isset($pas[$index]) ? $pas[$index] : null;
4557  } else {
4558  $args[$ki] = $this->getFamilyParameterValue($input->name);
4559  }
4560  } else {
4561  if ($attr->inArray()) $args[$ki] = $this->getMultipleRawValues($input->name, "", $index);
4562  else $args[$ki] = $this->getRawValue($input->name);
4563  }
4564  } else {
4565  if ($input->name == 'THIS') {
4566  $args[$ki] = & $this;
4567  } elseif ($input->name == 'K') {
4568  $args[$ki] = $index;
4569  } else {
4570 
4571  $args[$ki] = $input->name; // not an attribute just text
4572 
4573  }
4574  }
4575  }
4576  }
4577  $value = call_user_func_array(array(
4578  $staticClass,
4579  $methodName,
4580  ) , $args);
4581  }
4582  } else {
4583  $err = sprintf(_("Method [%s] not exists") , $method);
4585  error_log(print_r(getDebugStack() , true));
4586  return null;
4587  }
4588  }
4589  return $value;
4590  }
4591  /**
4592  * verify attribute constraint
4593  *
4594  * @param string $attrid attribute identifier
4595  * @param int $index index in case of multiple values
4596  * @return array array of 2 items ("err" + "sug").
4597  * The err is the string error message (empty means no error)
4598  * The sug is an array of possibles corrections
4599  */
4600  final public function verifyConstraint($attrid, $index = - 1)
4601  {
4602  $ok = array(
4603  "err" => "",
4604  "sug" => array()
4605  );
4606  /*
4607  * @var NormalAttribute $oattr
4608  */
4609  $oattr = $this->getAttribute($attrid);
4610  if (strlen(trim($oattr->phpconstraint)) > 1) {
4611  $ko = array(
4612  "err" => sprintf(_("method %s not found") , $oattr->phpconstraint) ,
4613  "sug" => array()
4614  );
4615  $res = $this->applyMethod($oattr->phpconstraint, $ko, $index);
4616 
4617  if ($res !== true) {
4618  if (!is_array($res)) {
4619  if ($res === false) $res = array(
4620  "err" => _("constraint error") ,
4621  "sug" => array()
4622  );
4623  elseif (is_string($res)) $res = array(
4624  "err" => $res,
4625  "sug" => array()
4626  );
4627  } elseif (!empty($res["sug"]) && (!is_array($res["sug"]))) {
4628  $res["sug"] = array(
4629  $res["sug"]
4630  );
4631  }
4632  if (is_array($res) && $res["err"] != "") $this->constraintbroken = "[$attrid] " . $res["err"];
4633  return $res;
4634  }
4635  }
4636 
4637  return $ok;
4638  }
4639  /**
4640  * verify if constraint ore OK
4641  * @param boolean $stoptofirst stop in first constraint error
4642  * @param array &$info set of information about constraint test
4643  * @return string error message (empty means no error)
4644  */
4645  final public function verifyAllConstraints($stoptofirst = true, &$info = array())
4646  {
4647  $err = "";
4648 
4649  $listattr = $this->GetNormalAttributes();
4650  foreach ($listattr as $v) {
4651  if (strlen($v->phpconstraint) > 1) {
4652  if ($v->inArray()) {
4653  $tv = $this->getMultipleRawValues($v->id);
4654  for ($i = 0; $i < count($tv); $i++) {
4655  $res = $this->verifyConstraint($v->id, $i);
4656  if ($res["err"] != "") {
4657  $info[$v->id . $i] = array(
4658  "id" => $v->id,
4659  "label" => $v->getLabel() ,
4660  "sug" => $res["sug"],
4661  "err" => $res["err"],
4662  "index" => $i,
4663  "pid" => $v->fieldSet->id
4664  );
4665  if ($stoptofirst) return sprintf("[%s] %s", $v->getLabel() , $res["err"]);
4666  $err = $res["err"];
4667  }
4668  }
4669  } else {
4670  $res = $this->verifyConstraint($v->id);
4671  if ($res["err"] != "") {
4672  $info[$v->id] = array(
4673  "id" => $v->id,
4674  "label" => $v->getLabel() ,
4675  "pid" => $v->fieldSet->id,
4676  "sug" => $res["sug"],
4677  "err" => $res["err"]
4678  );
4679  if ($stoptofirst) return sprintf("[%s] %s", $v->getLabel() , $res["err"]);
4680  $err = $res["err"];
4681  }
4682  }
4683  }
4684  }
4685  return $err;
4686  }
4687  /**
4688  * return the first attribute of type 'file' false if no file
4689  * @return NormalAttribute|bool
4690  */
4691  final public function getFirstFileAttributes()
4692  {
4693  $t = $this->GetFileAttributes();
4694  if (count($t) > 0) return current($t);
4695  return false;
4696  }
4697  /**
4698  * Add a comment line in history document
4699  * note : modify is call automatically
4700  * @api Add a comment message in history document
4701  * @param string $comment the comment to add
4702  * @param int $level level of comment DocHisto::INFO, DocHisto::ERROR, DocHisto::NOTICE DocHisto::MESSAGE, DocHisto::WARNING
4703  * @param string $code use when memorize notification
4704  * @param string $uid user identifier : by default its the current user
4705  * @return string error message
4706  */
4707  final public function addHistoryEntry($comment = '', $level = DocHisto::INFO, $code = '', $uid = '')
4708  {
4709  global $action;
4710  if ($this->id == "") return '';
4711 
4712  $h = new DocHisto($this->dbaccess);
4713 
4714  $h->id = $this->id;
4715  $h->initid = $this->initid;
4716  if (!isUTF8($comment)) $comment = utf8_encode($comment);
4717  $h->comment = $comment;
4718  $h->date = date("d-m-Y H:i:s");
4719  if ($uid > 0) {
4720  $u = new Account("", $uid);
4721  $h->uid = $u->id;
4722  $h->uname = sprintf("%s %s", $u->firstname, $u->lastname);
4723  } else {
4724  $h->uname = sprintf("%s %s", $action->user->firstname, $action->user->lastname);
4725  $h->uid = $action->user->id;
4726  }
4727  $h->level = $level;
4728  $h->code = $code;
4729 
4730  $err = $h->Add();
4731  if ($level == HISTO_ERROR) {
4732  error_log(sprintf("document %s [%d] : %s", $this->title, $this->id, $comment));
4733  }
4734  return $err;
4735  }
4736  /**
4737  * Add a comment line in history document
4738  * note : modify is call automatically
4739  * @param string $comment the comment to add
4740  * @param int $level level of comment DocHisto::INFO, DocHisto::ERROR, DocHisto::NOTICE DocHisto::MESSAGE, DocHisto::WARNING
4741  * @param string $code use when memorize notification
4742  * @param string $uid user identifier : by default its the current user
4743  * @deprecated use {@link Doc::addHistoryEntry} instead
4744  * @see Doc::addHistoryEntry
4745  * @return string error message
4746  */
4747  final public function addComment($comment = '', $level = DocHisto::INFO, $code = '', $uid = '')
4748  {
4750  return $this->addHistoryEntry($comment, $level, $code, $uid);
4751  }
4752  /**
4753  * Add a log entry line in log document
4754  *
4755  * @param string $comment the comment to add
4756  * @param string $level level of comment
4757  * @param string $code use when memorize notification
4758  * @param string $arg serialized object
4759  * @param string $uid user identifier : by default its the current user
4760  * @return string error message
4761  */
4762  final public function addLog($code = '', $arg = '', $comment = '', $level = '', $uid = '')
4763  {
4764  global $action;
4765  if (($this->id == "") || ($this->doctype == 'T')) return '';
4766 
4767  include_once ("FDL/Class.DocLog.php");
4768  $h = new DocLog($this->dbaccess);
4769  $h->id = $this->id;
4770  $h->initid = $this->initid;
4771  $h->title = $this->title;
4772  if (!isUTF8($comment)) $comment = utf8_encode($comment);
4773  $h->comment = $comment;
4774 
4775  if ($uid > 0) {
4776  $u = new Account("", $uid);
4777  $h->uid = $u->id;
4778  $h->uname = sprintf("%s %s", $u->firstname, $u->lastname);
4779  } else {
4780  $h->uname = sprintf("%s %s", $action->user->firstname, $action->user->lastname);
4781  $h->uid = $action->user->id;
4782  }
4783  $h->level = $level ? $level : DocLog::LOG_NOTIFY;
4784  $h->code = $code;
4785  if ($arg) $h->arg = serialize($arg);
4786 
4787  $err = $h->Add();
4788  return $err;
4789  }
4790  /**
4791  * Get history for the document
4792  * @param bool $allrev set true if want for all revision
4793  *
4794  * @param string $code code filter
4795  * @param int $limit limit of items returned
4796  * @return array of different comment
4797  */
4798  public function getHisto($allrev = false, $code = "", $limit = 0)
4799  {
4800  include_once ("Class.QueryDb.php");
4801  $q = new QueryDb($this->dbaccess, "dochisto");
4802  if ($allrev) $q->AddQuery("initid=" . $this->initid);
4803  else $q->AddQuery("id=" . $this->id);
4804  if ($code) $q->addQuery(sprintf("code='%s'", pg_escape_string($code)));
4805  $q->order_by = "date desc";
4806  $l = $q->Query(0, $limit, "TABLE");
4807 
4808  if (is_array($l)) return $l;
4809  return array();
4810  }
4811  /**
4812  * Add a application tag for the document
4813  * if it is already set no set twice
4814  * A application tag must not contains "\n" character
4815  * @param string $tag the tag to add
4816  * @return string error message
4817  */
4818  final public function addATag($tag)
4819  {
4820  $err = "";
4821  if (strpos($tag, "\n") !== false) return ErrorCode::getError('DOC0121', $tag, $this->id);
4822  if (!$tag) return ErrorCode::getError('DOC0122', $this->id);
4823  if ($this->atags == "") {
4824  $this->atags = $tag;
4825  $err = $this->modify(true, array(
4826  "atags"
4827  ) , true);
4828  } else {
4829  if (!$this->getATag($tag)) {
4830  $this->atags.= "\n$tag";
4831  $err = $this->modify(true, array(
4832  "atags"
4833  ) , true);
4834  }
4835  }
4836  return $err;
4837  }
4838  /**
4839  * Return true if application tag is present
4840  *
4841  * @param string $tag the tag to search
4842  * @return bool
4843  */
4844  final public function getATag($tag)
4845  {
4846  if ($this->atags == "") return false;
4847  return (preg_match(sprintf('/^(%s)$/m', preg_quote($tag, '/')) , $this->atags) > 0);
4848  }
4849  /**
4850  * Delete a application tag for the document
4851  *
4852  * @param string $tag the tag to delete
4853  * @return string error message
4854  */
4855  final public function delATag($tag)
4856  {
4857  $err = "";
4858  if ($this->atags == "") return "";
4859  $atags = preg_replace(sprintf('/^%s$/m', preg_quote($tag, '/')) , '', $this->atags);
4860  $atags = str_replace("\n\n", "\n", $atags);
4861  $atags = preg_replace("/\n$/m", '', $atags);
4862  $atags = preg_replace("/^\n/", '', $atags);
4863  if ($atags != $this->atags) {
4864  $this->atags = $atags;
4865  $err = $this->modify(true, array(
4866  "atags"
4867  ) , true);
4868  }
4869  return $err;
4870  }
4871  /**
4872  * Add a user tag for the document
4873  * if it is already set no set twice
4874  * @param int $uid the system user identifier
4875  * @param string $tag the key tag
4876  * @param string $datas a comment or a value for the tag
4877  * @param bool $allrevision set to false if attach a tag to a specific version
4878  * @return string error message
4879  */
4880  final public function addUTag($uid, $tag, $datas = "", $allrevision = true)
4881  {
4882  if (!$this->initid) return "";
4883  if ($tag == "") return _("no user tag specified");
4884  $this->delUTag($uid, $tag, $allrevision);
4885 
4886  global $action;
4887  $h = new DocUTag($this->dbaccess);
4888 
4889  $h->id = $this->id;
4890  $h->initid = $this->initid;
4891  $h->fixed = ($allrevision) ? 'false' : 'true';
4892  $h->date = date("d-m-Y H:i:s");
4893  if ($uid > 0) {
4894  $u = new Account("", $uid);
4895  $h->uid = $u->id;
4896  $h->uname = sprintf("%s %s", $u->firstname, $u->lastname);
4897  }
4898  $h->fromuid = $action->user->id;
4899 
4900  $h->tag = $tag;
4901  $h->comment = $datas;
4902 
4903  $err = $h->Add();
4904  return $err;
4905  }
4906  /**
4907  * Test if current user has the user tag specified
4908  *
4909  * @param string $tag the tag to verify
4910  * @param bool $allrevision set to false to verify a tag to a specific version
4911  * @return bool
4912  */
4913  final public function hasUTag($tag, $allrevision = true)
4914  {
4915  if (!$this->initid) return false;
4916  include_once ("FDL/Class.DocUTag.php");
4917  $docid = ($allrevision) ? $this->initid : $this->id;
4918  $utag = new DocUTag($this->dbaccess, array(
4919  $docid,
4920  $this->userid,
4921  $tag
4922  ));
4923  return $utag->isAffected();
4924  }
4925  /**
4926  * Get current user tag specified
4927  *
4928  * @param string $tag the tag to verify
4929  * @param bool $allrevision set to false to get a tag to a specific version
4930  * @param int $uid system user identifier
4931  * @return bool|DocUTag
4932  * @throws \Dcp\Db\Exception
4933  */
4934  final public function getUTag($tag, $allrevision = true, $uid = null)
4935  {
4936  if (!$this->initid) return "";
4937  if ($uid === null) {
4938  $uid = $this->userid;
4939  }
4940 
4941  include_once ("FDL/Class.DocUTag.php");
4942  $q = new QueryDb($this->dbaccess, "docUTag");
4943  $q->addQuery("uid=" . intval($uid));
4944  if ($tag) $q->addQuery("tag = '" . pg_escape_string($tag) . "'");
4945  if ($allrevision) $q->addQuery("initid = " . $this->initid);
4946  else $q->addQuery("id = " . $this->id);
4947  $q->order_by = "id desc";
4948  $r = $q->Query(0, 1);
4949  if ($q->nb == 1) return $r[0];
4950  return false;
4951  }
4952  /**
4953  * Remove a user tag for the document
4954  * if it is already set no set twice
4955  * @param int $uid the system user identifier
4956  * @param string $tag the tag to add
4957  * @param bool $allrevision set to false to del a tag to a specific version
4958  * @return string error message
4959  */
4960  final public function delUTag($uid, $tag, $allrevision = true)
4961  {
4962  if ($tag == "") {
4963  return _("no user tag specified");
4964  }
4965 
4966  if ($allrevision) {
4967  $err = $this->exec_query(sprintf("delete from docutag where initid=%d and tag='%s' and uid=%d", $this->initid, pg_escape_string($tag) , $uid));
4968  } else {
4969  $err = $this->exec_query(sprintf("delete from docutag where id=%d and tag='%s' and uid=%d", $this->id, pg_escape_string($tag) , $uid));
4970  }
4971  return $err;
4972  }
4973  /**
4974  * Remove all user tag for the document
4975  *
4976  * @param int $uid the system user identifier
4977  * @return string error message
4978  */
4979  final public function delUTags($uid = 0)
4980  {
4981  if (!$this->initid) return "";
4982  if (!$uid) $uid = $this->userid;
4983  $err = $this->exec_query(sprintf("delete from docutag where initid=%d and uid=%d", $this->initid, $uid));
4984 
4985  return $err;
4986  }
4987  /**
4988  * Refresh all user tag for the document in case of revision
4989  * @return string error message
4990  */
4991  final public function refreshUTags()
4992  {
4993  $err = '';
4994  if (!$this->initid) return "";
4995  include_once ("FDL/Class.DocUTag.php");
4996  $q = new QueryDb($this->dbaccess, "docUTag");
4997  $q->Query(0, 0, "TABLE", sprintf("update docutag set id=%d where initid=%d and (not fixed)", $this->id, $this->initid));
4998 
4999  return $err;
5000  }
5001  /**
5002  * search all user tag for the document
5003  * @param string $tag tag to search
5004  * @param boolean $allrevision view tags for all revision
5005  * @param boolean $allusers view tags of all users
5006  * @return array user tags key=>value
5007  */
5008  final public function searchUTags($tag = "", $allrevision = true, $allusers = false)
5009  {
5010  if (!$this->initid) return "";
5011  include_once ("FDL/Class.DocUTag.php");
5012  $q = new QueryDb($this->dbaccess, "docUTag");
5013  if (!$allusers) $q->addQuery("uid=" . intval($this->userid));
5014  if ($tag) $q->addQuery("tag = '" . pg_escape_string($tag) . "'");
5015  if ($allrevision) $q->addQuery("initid = " . $this->initid);
5016  else $q->addQuery("id = " . $this->id);
5017  $r = $q->Query(0, 0, "TABLE");
5018  if ($q->nb == 0) $r = array();
5019  return $r;
5020  }
5021  /**
5022  * get ask for current users
5023  * @param bool $control if false all associated askes else only askes available for current user
5024  * @return array
5025  */
5026  public function getWasks($control = true)
5027  {
5028  $t = array();
5029  if ($this->wid > 0 && $this->locked == - 1 && $this->doctype != 'Z' && $this->state) {
5030  /*
5031  * @var WDoc $wdoc
5032  */
5033  $wdoc = new_doc($this->dbaccess, $this->wid);
5034  if ($wdoc->isAlive()) {
5035  $wdoc->set($this);
5036  $waskids = $wdoc->getDocumentWasks($this->state, $control);
5037  foreach ($waskids as $k => $waskid) {
5038  /**
5039  * @var \Dcp\Family\WASK $wask
5040  */
5041  $wask = new_doc($this->dbaccess, $waskid);
5042  if ($wask->isAlive()) {
5043  $ut = $this->getUTag("ASK_" . $wask->id, false);
5044  if ($ut) $answer = $ut->comment;
5045  else $answer = "";
5046  $t[] = array(
5047  "waskid" => $wask->id,
5048  "ask" => $wask->getRawValue("was_ask") ,
5049  "key" => $answer,
5050  "label" => $wask->getAskLabel($answer)
5051  );
5052  }
5053  }
5054  }
5055  }
5056  return $t;
5057  }
5058  /**
5059  * set a answer for a document for a ask (for current user)
5060  * @param int $waskid the identifier of wask
5061  * @param string $answer new answer response
5062  * @return string error message
5063  */
5064  function setWaskAnswer($waskid, $answer)
5065  {
5066  $err = _("setWaskAnswer::invalid parameters");
5067  $waskid = intval($waskid);
5068  if ($waskid && $answer) {
5069  if (is_array($answer)) $answer = $this->arrayToRawValue($answer);
5070  $err = $this->addUTag($this->userid, "ASK_" . intval($waskid) , $answer, false);
5071  return $err;
5072  }
5073  return $err;
5074  }
5075  /**
5076  * all ask are answer ?
5077  * @return bool true if all ask are answer or when has no askes
5078  */
5079  function askIsCompleted()
5080  {
5081  $ans = $this->getWasks();
5082  foreach ($ans as $an) {
5083  if (!$an["key"]) return false;
5084  }
5085  return true;
5086  }
5087  /**
5088  * return the latest document id in history of a document which has ask
5089  * @return int the identifier
5090  */
5092  {
5093  if (!$this->wid) return false;
5094  $ldoc = $this->GetRevisions("TABLE");
5095  /*
5096  * @var WDoc $wdoc
5097  */
5098  $wdoc = new_doc($this->dbaccess, $this->wid);
5099  if ($wdoc->isAlive()) {
5100  $wdoc->set($this);
5101  foreach ($ldoc as $k => $v) {
5102  $aask = $wdoc->attrPrefix . "_ASKID" . ($v["state"]);
5103  if ($v["locked"] == - 1 && $wdoc->getRawValue($aask)) {
5104  if ($wdoc->getRawValue($aask)) return $v["id"];
5105  }
5106  }
5107  }
5108  return false;
5109  }
5110  /**
5111  * verify if document is really fixed (verify in database)
5112  * @return bool
5113  */
5114  function isFixed()
5115  {
5116  return isFixedDoc($this->dbaccess, $this->id);
5117  }
5118  /**
5119  * Create a new revision of a document
5120  * the current document is revised (became a fixed document)
5121  * a new revision is created, a new identifier if set
5122  * @api Create a new revision of a document
5123  * @param string $comment the comment of the revision
5124  * @return string error text (empty if no error)
5125  */
5126  final public function revise($comment = '')
5127  {
5128  // first control
5129  if ($this->locked == - 1) return _("document already revised");
5130  if ($this->isFixed()) {
5131  $err = _("document already revised");
5132  $this->addHistoryEntry($err, DocHisto::ERROR, "REVERROR");
5133  return $err;
5134  }
5135  $err = $this->preRevise();
5136  if ($err) return $err;
5137  if (!$this->withoutControl) {
5138  $err = $this->Control("edit");
5139  if ($err != "") return ($err);
5140  }
5141  $fdoc = $this->getFamilyDocument();
5142 
5143  if ($fdoc->schar == "S") return sprintf(_("the document of %s family cannot be revised") , $fdoc->title);
5146  $postitid = $this->postitid; // transfert post-it to latest revision
5147  $this->locked = - 1; // the file is archived
5148  $this->lmodify = 'N'; // not locally modified
5149  $this->allocated = 0; // cannot allocated fixed document
5150  $this->owner = $this->userid; // rev user
5151  $this->postitid = 0;
5152  $date = gettimeofday();
5153  $this->revdate = $date['sec']; // change rev date
5154  $point = "dcp:revision" . $this->id;
5155  $this->savePoint($point);
5156  if ($comment != '') $this->addHistoryEntry($comment, DocHisto::MESSAGE, "REVISION");
5157  $err = $this->modify();
5158  if ($err != "") {
5159  $this->rollbackPoint($point);
5160  //$this->exec_query("rollback;");
5161  $this->select($this->id); // reset db values
5162  return $err;
5163  }
5164  // double control
5165  if (!$this->isFixed()) {
5166  $err = sprintf("track error revision [%s]", pg_last_error($this->dbid));
5167  $this->addHistoryEntry($err, DocHisto::ERROR, "REVERROR");
5168  $this->commitPoint($point);
5169  return $err;
5170  }
5171 
5172  $fa = $this->GetFileAttributes(true); // copy cached values
5173  $ca = array();
5174  foreach ($fa as $k => $v) {
5175  $ca[] = $v->id . "_txt";
5176  }
5177  $this->affectColumn($ca, false);
5178  foreach ($ca as $a) {
5179  if ($this->$a != "") $this->fields[$a] = $a;
5180  }
5181  //$listvalue = $this->GetValues(); // save copy of values
5182  // duplicate values
5183  $olddocid = $this->id;
5184  $this->id = "";
5185 
5186  if ($locked > 0) $this->locked = $locked; // report the lock
5187  else $this->locked = 0;
5188  $this->allocated = $allocated; // report the allocate
5189  $this->revision = $this->revision + 1;
5190  $this->postitid = $postitid;
5191 
5192  $err = $this->Add();
5193  if ($err != "") {
5194  // restore last revision
5195  // $this->exec_query("rollback;");
5196  $this->rollbackPoint($point);
5197 
5198  $this->select($olddocid); // reset db values
5199  return $err;
5200  }
5201 
5202  $this->commitPoint($point);
5203 
5204  $this->refresh(); // to recompute possible dynamic profil variable
5205  if ($this->dprofid > 0) $this->setProfil($this->dprofid); // recompute profil if needed
5206  $err = $this->modify(); // need to applicate SQL triggers
5207  $this->UpdateVaultIndex();
5208  $this->refreshUTags();
5209  if ($err == "") {
5210  $this->addLog("revision", array(
5211  "id" => $this->id,
5212  "initid" => $this->initid,
5213  "revision" => $this->revision,
5214  "title" => $this->title,
5215  "fromid" => $this->fromid,
5216  "fromname" => $this->fromname
5217  ));
5218  // max revision
5219  $fdoc = $this->getFamilyDocument();
5220  $maxrev = intval($fdoc->maxrev);
5221  if ($maxrev > 0) {
5222  if ($this->revision > $maxrev) {
5223  // need delete first revision
5224 
5225  /**
5226  * @var $revs array
5227  */
5228  $revs = $this->getRevisions("TABLE", "ALL");
5229  for ($i = $maxrev; $i < count($revs); $i++) {
5230  $d = getDocObject($this->dbaccess, $revs[$i]);
5231  if ($d) $d->_destroy(true);
5232  }
5233  }
5234  }
5235  $msg = $this->postRevise();
5236  if ($msg) $this->addHistoryEntry($msg, DocHisto::MESSAGE, "POSTREVISE");
5237  }
5238 
5239  return $err;
5240  }
5241  /**
5242  * Create a new revision of a document
5243  * the current document is revised (became a fixed document)
5244  * a new revision is created, a new identifier if set
5245  * @deprecated use {@link Doc::revise} instead
5246  * @see Doc::revise
5247  * @param string $comment the comment of the revision
5248  * @return string error text (empty if no error)
5249  */
5250  final public function addRevision($comment = '')
5251  {
5253  return $this->revise($comment);
5254  }
5255  /**
5256  * Set a free state to the document
5257  * for the document without workflow
5258  * a new revision is created
5259  * @param string $newstateid the document id of the state (FREESTATE family)
5260  * @param string $comment the comment of the state change
5261  * @param bool $revision if false no revision are made
5262  * @return string error text (empty if no error)
5263  */
5264  final public function changeFreeState($newstateid, $comment = '', $revision = true)
5265  {
5266  if ($this->wid > 0) return sprintf(_("cannot set free state in workflow controlled document %s") , $this->title);
5267  if ($this->wid == - 1) return sprintf(_("cannot set free state for document %s: workflow not allowed") , $this->title);
5268  if (!$this->isRevisable()) return sprintf(_("cannot set free state for document %s: document cannot be revised") , $this->title);
5269  if ($newstateid == 0) {
5270  $this->state = "";
5271  $err = $this->modify(false, array(
5272  "state"
5273  ));
5274  if ($err == "") {
5275  $comment = sprintf(_("remove state : %s") , $comment);
5276  if ($revision) $err = $this->revise($comment);
5277  else $err = $this->addHistoryEntry($comment);
5278  }
5279  } else {
5280 
5281  $state = new_doc($this->dbaccess, $newstateid);
5282  if (!$state->isAlive()) return sprintf(_("invalid freestate document %s") , $newstateid);
5283  if ($state->fromid != 39) return sprintf(_("not a freestate document %s") , $state->title);
5284 
5285  $this->state = $state->id;
5286  $err = $this->modify(false, array(
5287  "state"
5288  ));
5289  if ($err == "") {
5290  $comment = sprintf(_("change state to %s : %s") , $state->title, $comment);
5291  if ($revision) $err = $this->revise($comment);
5292  else $err = $this->addHistoryEntry($comment);
5293  }
5294  }
5295  return $err;
5296  }
5297  /**
5298  * set state for a document controled by a workflow
5299  * apply associated transaction
5300  *
5301  * @api set state for a document controled by a workflow
5302  * @param string $newstate the new state
5303  * @param string $comment optional comment to set in history
5304  * @param bool $force is true when it is the second passage (without interactivity)
5305  * @param bool $withcontrol set to false if you want to not verify control permission ot transition
5306  * @param bool $wm1 set to false if you want to not apply m1 methods
5307  * @param bool $wm2 set to false if you want to not apply m2 methods
5308  * @param bool $wneed set to false to not test required attributes
5309  * @param bool $wm0 set to false if you want to not apply m0 methods
5310  * @param bool $wm3 set to false if you want to not apply m3 methods
5311  * @param string $msg return message from m2 or m3
5312  * @return string error message empty if no error
5313  */
5314  final public function setState($newstate, $comment = '', $force = false, $withcontrol = true, $wm1 = true, $wm2 = true, $wneed = true, $wm0 = true, $wm3 = true, &$msg = '')
5315  {
5316  if ($newstate == "") return _("no state specified");
5317  if (!$this->wid) return _("document is not controlled by a workflow");
5318  /*
5319  * @var WDoc $wdoc
5320  */
5321  $wdoc = new_doc($this->dbaccess, $this->wid);
5322  if (!$wdoc->isAlive()) return _("assigned workflow is not alive");
5323  try {
5324  $wdoc->Set($this);
5325  $err = $wdoc->ChangeState($newstate, $comment, $force, $withcontrol, $wm1, $wm2, $wneed, $wm0, $wm3, $msg);
5326  }
5327  catch(Dcp\Exception $e) {
5328  $err = sprintf(_("Unexpected transition error on workflow %s [%d] : %s") , $wdoc->title, $wdoc->id, $e->getMessage());
5329  errorLogException($e);
5330  }
5331  return $err;
5332  }
5333  /**
5334  * return the state of a document
5335  * if document has workflow it is the key
5336  * if document state is a free state it is the name of the state
5337  *
5338  * @api get the state of a document
5339  * @return string the state - empty if no state
5340  */
5341  public function getState()
5342  {
5343  if ($this->wid > 0) return $this->state;
5344  if (is_numeric($this->state) && ($this->state > 0)) {
5345  $state = $this->getTitle($this->state);
5346  return $state;
5347  }
5348 
5349  return $this->state;
5350  }
5351  /**
5352  * return the color associated for the state of a document
5353  * if document has workflow : the color state
5354  * if document state is a free state the color
5355  *
5356  * @param string $def default color if state not found or color is empty
5357  * @return string the color of the state - empty if no state
5358  */
5359  public function getStateColor($def = "")
5360  {
5361  if ($this->wid > 0) {
5362  /*
5363  * @var WDoc $wdoc
5364  */
5365  $wdoc = new_Doc($this->dbaccess, $this->wid);
5366  if ($wdoc->isAffected()) return $wdoc->getColor($this->state, $def);
5367  } else {
5368  if (is_numeric($this->state) && ($this->state > 0)) {
5369  $state = $this->getDocValue($this->state, "frst_color", $def);
5370  return $state;
5371  }
5372  }
5373  return $def;
5374  }
5375  /**
5376  * return the action associated for the state of a document
5377  * if document has workflow : the action label description
5378  * if document state is a free state : state description
5379  *
5380  * @param string $def default activity is activity is empty
5381  * @return string the color of the state - empty if no state
5382  */
5383  final public function getStateActivity($def = "")
5384  {
5385  if ($this->wid > 0) {
5386  /*
5387  * @var WDoc $wdoc
5388  */
5389  $wdoc = new_Doc($this->dbaccess, $this->wid);
5390  if ($wdoc->isAffected()) return $wdoc->getActivity($this->state, $def);
5391  } else {
5392  if (is_numeric($this->state) && ($this->state > 0)) {
5393  $stateact = $this->getDocValue($this->state, "frst_desc", $def);
5394  return $stateact;
5395  }
5396  }
5397  return $def;
5398  }
5399  /**
5400  * return state label if ficed document else activity label
5401  * if not activity return state
5402  * @return string localized state label
5403  */
5404  final public function getStatelabel()
5405  {
5406  if ($this->locked == - 1) $stateValue = $this->getState();
5407  else $stateValue = $this->getStateActivity($this->getState());
5408  return (empty($stateValue) ? '' : _($stateValue));
5409  }
5410  /**
5411  * return the copy (duplication) of the document
5412  * the copy is created to the database
5413  * the profil of the copy is the default profil according to his family
5414  * the copy is not locked and if it is related to a workflow, his state is the first state
5415  * @deprecated use {@link Doc::duplicate} instead
5416  * @see Doc::duplicate
5417  * @param bool $temporary if true the document create it as temporary document
5418  * @param bool $control if false don't control acl create (generaly use when temporary is true)
5419  * @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
5420  * @param bool $copyfile if true duplicate files of the document
5421  * @return Doc in case of error return a string that indicate the error
5422  */
5423  final public function copy($temporary = false, $control = true, $linkfld = false, $copyfile = false)
5424  {
5426  return $this->duplicate($temporary, $control, $linkfld, $copyfile);
5427  }
5428  /**
5429  * return the copy (duplication) of the document
5430  * the copy is created to the database
5431  * the profil of the copy is the default profil according to his family
5432  * the copy is not locked and if it is related to a workflow, his state is the first state
5433  * @api duplicate document
5434  * @param bool $temporary if true the document create it as temporary document
5435  * @param bool $control if false don't control acl create (generaly use when temporary is true)
5436  * @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
5437  * @param bool $copyfile if true duplicate files of the document
5438  * @return Doc|string in case of error return a string that indicate the error
5439  */
5440  final public function duplicate($temporary = false, $control = true, $linkfld = false, $copyfile = false)
5441  {
5442  if ($this->fromid == '') {
5443  throw new Dcp\Exception(ErrorCode::getError('DOC0203'));
5444  }
5445  $copy = createDoc($this->dbaccess, $this->fromid, $control);
5446  if (!is_object($copy)) return false;
5447  /*
5448  * @var Doc $copy
5449  */
5450  $err = $copy->transfertValuesFrom($this);
5451  if ($err != "") return $err;
5452 
5453  $copy->id = "";
5454  $copy->initid = "";
5455  $copy->revision = "0";
5456  $copy->locked = "0";
5457  $copy->allocated = "0";
5458  $copy->state = "";
5459  $copy->icon = $this->icon;;
5460 
5461  if ($temporary) {
5462  $copy->doctype = "T";
5463  $copy->profid = 0;
5464  $copy->dprofid = 0;
5465  } else {
5466  $cdoc = $this->getFamilyDocument();
5467  $copy->setProfil($cdoc->cprofid);
5468  }
5469 
5470  $err = $copy->preDuplicate($this);
5471  if ($err != "") return $err;
5472 
5473  $err = $copy->Add();
5474  if ($err != "") return $err;
5475  $copy->addHistoryEntry(sprintf(_("copy from document #%d -%s-") , $this->id, $this->title));
5476 
5477  if ($copyfile) $copy->duplicateFiles();
5478 
5479  $msg = $copy->postDuplicate($this);
5480  if ($msg != "") {
5481  $copy->addHistoryEntry($msg, HISTO_MESSAGE);
5482  }
5483 
5484  $copy->Modify();
5485  if ($linkfld && method_exists($copy, "insertFolder")) {
5486  /*
5487  * @var Dir $copy
5488  */
5489  $copy->insertFolder($this->initid);
5490  }
5491 
5492  return $copy;
5493  }
5494  /**
5495  * call before copy document
5496  * if return error message duplicate is aborted
5497  * @api hook called before duplicate document
5498  * @see Doc::duplicate
5499  * @param Doc $copyfrom original document
5500  * @return string
5501  */
5502  function preDuplicate(
5503  /* @noinspection PhpUnusedParameterInspection */ & $copyfrom)
5504  {
5505  // to be defined in child class
5506  return "";
5507  }
5508  /**
5509  * call before copy document
5510  * if return error message duplicate is aborted
5511  * @deprecated hook use {@link Doc::preDuplicate} instead
5512  * @see Doc::preDuplicate
5513  * @param Doc $copyfrom
5514  * @return string
5515  */
5516  function preCopy(
5517  /* @noinspection PhpUnusedParameterInspection */ & $copyfrom)
5518  {
5519  // to be defined in child class
5520  return "";
5521  }
5522  /**
5523  * call after copy document
5524  * @api hook called after duplicate document
5525  * @see Doc::duplicate
5526  * @param Doc $copyfrom
5527  * @return string
5528  */
5529  function postDuplicate(
5530  /* @noinspection PhpUnusedParameterInspection */ & $copyfrom)
5531  {
5532  // to be defined in child class
5533  return "";
5534  }
5535  /**
5536  * call after copy document
5537  * @api hook called after duplicate document
5538  * @deprecated use {@link Doc::postDuplicate} hook instead
5539  * @see Doc::postDuplicate
5540  * @param Doc $copyfrom
5541  * @return string
5542  */
5543  function postCopy(
5544  /* @noinspection PhpUnusedParameterInspection */ & $copyfrom)
5545  {
5546  // to be defined in child class
5547  return "";
5548  }
5549 
5550  final public function translate($docid, $translate)
5551  {
5552  $doc = new_Doc($this->dbaccess, $docid);
5553  if ($doc->isAlive()) {
5554  foreach ($translate as $afrom => $ato) {
5555  $this->setValue($ato, $doc->getRawValue($afrom));
5556  }
5557  }
5558  }
5559  /**
5560  * Put document in an archive
5561  * @param \Dcp\Family\ARCHIVING $archive the archive document
5562  * @return string error message
5563  */
5564  final public function archive(&$archive)
5565  {
5566  $err = "";
5567  if ($this->archiveid == 0) {
5568  if ($this->doctype == "C") $err = sprintf("families cannot be archieved");
5569  elseif (!$this->withoutControl) $err = $this->control("edit");
5570  if ($err == "") {
5571  $this->locked = 0;
5572  $this->archiveid = $archive->id;
5573  $this->dprofid = ($this->dprofid > 0) ? (-$this->dprofid) : (-abs($this->profid));
5574  $archprof = $archive->getRawValue("arc_profil");
5575  $this->profid = $archprof;
5576  $err = $this->modify(true, array(
5577  "locked",
5578  "archiveid",
5579  "dprofid",
5580  "profid"
5581  ) , true);
5582  if (!$err) {
5583  $this->addHistoryEntry(sprintf(_("Archiving into %s") , $archive->getTitle()) , HISTO_MESSAGE, "ARCHIVE");
5584  $this->addLog('archive', $archive->id, sprintf(_("Archiving into %s") , $archive->getTitle()));
5585  $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));
5586  }
5587  }
5588  } else $err = sprintf("document is already archived");
5589 
5590  return $err;
5591  }
5592  /**
5593  * Delete document in an archive
5594  * @param \Dcp\Family\ARCHIVING $archive the archive document
5595  *
5596  * @return string error message
5597  */
5598  final public function unArchive(&$archive)
5599  {
5600  $err = "";
5601 
5602  if ($this->archiveid == $archive->id) {
5603  if (!$this->withoutControl) $err = $this->control("edit");
5604  if ($err == "") {
5605  $this->locked = 0;
5606  $this->archiveid = ""; // set to null
5607  $restoreprofil = abs($this->dprofid);
5608  $this->dprofid = 0;
5609  $err = $this->setProfil($restoreprofil);
5610  if (!$err) $err = $this->modify(true, array(
5611  "locked",
5612  "archiveid",
5613  "dprofid",
5614  "profid"
5615  ) , true);
5616  if (!$err) {
5617  $this->addHistoryEntry(sprintf(_("Unarchiving from %s") , $archive->getTitle()) , HISTO_MESSAGE, "UNARCHIVE");
5618  $this->addLog('unarchive', $archive->id, sprintf(_("Unarchiving from %s") , $archive->getTitle()));
5619  $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));
5620  }
5621  }
5622  } else $err = sprintf("document not archived");
5623 
5624  return $err;
5625  }
5626  /**
5627  * lock document
5628  *
5629  * the auto lock is unlocked when the user discard edition or when he's modify document
5630  * @param bool $auto if true it is a automatic lock due to an edition (@see Doc::editcard()}
5631  * @param int $userid if set lock with another userid, the edit control will be disabled
5632  *
5633  * @return string error message, if no error empty string, if message
5634  * @see Doc::CanLockFile()
5635  * @see Doc::unlock()
5636  */
5637  final public function lock($auto = false, $userid = 0)
5638  {
5639 
5640  $err = "";
5641  if ($userid == 0) {
5642  $err = $this->CanLockFile();
5643  if ($err != "") return $err;
5645  } else {
5646  $this->disableEditControl();
5647  }
5648  // test if is not already locked
5649  if ($auto) {
5650  if (($userid != 1) && ($this->locked == 0)) {
5651  $this->locked = - $userid; // in case of auto lock the locked id is negative
5652  $err = $this->modify(false, array(
5653  "locked"
5654  ));
5655  if (!$err) $this->addLog('lock');
5656  }
5657  } else {
5658  if (($this->locked != $userid) || ($this->lockdomainid)) {
5659  $this->locked = $userid;
5660  $err = $this->modify(false, array(
5661  "locked"
5662  ));
5663  if (!$err) $this->addLog('lock');
5664  }
5665  }
5666  $this->enableEditControl();
5667 
5668  return $err;
5669  }
5670  /**
5671  * unlock document
5672  *
5673  * the automatic unlock is done only if the lock has been set automatically also
5674  * the explicit unlock, unlock in all case (if CanUnLockFile)
5675  * @param bool $auto if true it is a automatic unlock
5676  * @param bool $force if true no control oif can unlock
5677  *
5678  * @return string error message, if no error empty string
5679  * @see Doc::CanUnLockFile()
5680  * @see Doc::lock()
5681  */
5682  final public function unLock($auto = false, $force = false)
5683  {
5684  $err = '';
5685  if ($this->locked == 0) return "";
5686  if (!$force) $err = $this->CanUnLockFile();
5687  if ($err != "") return $err;
5688 
5689  if ($auto) {
5690  if ($this->locked < - 1) {
5691  $this->locked = "0";
5692  $this->modify(false, array(
5693  "locked"
5694  ));
5695  if (!$err) $this->addLog('unlock');
5696  }
5697  } else {
5698  if ($this->locked != - 1) {
5699  $this->locked = "0";
5700  $this->lockdomainid = '';
5701  $this->modify(false, array(
5702  "locked",
5703  "lockdomainid"
5704  ));
5705  if (!$err) $this->addLog('unlock');
5706  }
5707  }
5708 
5709  return "";
5710  }
5711  /**
5712  * allocate document
5713  *
5714  * affect a document to a user
5715  * @param int $userid the system identifier of the user to affect
5716  * @param string $comment message for allocation
5717  * @param bool $revision if false no revision are made
5718  * @param bool $autolock if false no lock are made
5719  *
5720  * @return string error message, if no error empty string, if message
5721  */
5722  final public function allocate($userid, $comment = "", $revision = false, $autolock = true)
5723  {
5724 
5725  $err = $this->canEdit();
5726  if ($err != "") $err = _("Affectation aborded") . "\n" . $err;
5727  if ($err == "") {
5728  $u = new Account("", $userid);
5729  if ($u->isAffected()) {
5730  if ($err != "") $err = _("Affectation aborded") . "\n" . $err;
5731  // no test if allocated can edit document
5732  //$err=$this->ControlUser($u->id,"edit");
5733  //if ($err != "") $err=sprintf(_("Affectation aborded\n%s for user %s %s"),$err,$u->firstname,$u->lastname);
5734  if ($err == "") {
5735  $this->addHistoryEntry(sprintf(_("Affected to %s %s") , $u->firstname, $u->lastname));
5736  if ($comment) {
5737  if ($revision) {
5738  $this->revise(sprintf(_("Affected for %s") , $comment));
5739  } else {
5740  $this->addHistoryEntry(sprintf(_("Affected for %s") , $comment));
5741  }
5742  }
5743  $this->addLog('allocate', array(
5744  "allocated" => array(
5745  "id" => $u->id,
5746  "firstname" => $u->firstname,
5747  "lastname" => $u->lastname
5748  )
5749  ));
5750 
5751  $this->delUTag($this->userid, "AFFECTED"); // TODO need delete all AFFECTED tag
5752  $this->addUTag($userid, "AFFECTED", $comment);
5753  if ($autolock) $err = $this->lock(false, $userid);
5754  }
5755  } else {
5756  $err = _("Affectation aborded : user not know");
5757  }
5758  }
5759  if ($err == "") {
5760  $this->allocated = $userid;
5761  $this->modify(true, array(
5762  "allocated"
5763  ) , true);
5764  }
5765 
5766  return $err;
5767  }
5768  /**
5769  * unallocate document
5770  *
5771  * unaffect a document to a user
5772  * only the allocated user can unallocate and also users which has unlock acl
5773  * @param string $comment message for unallocation
5774  * @param bool $revision if false no revision are made
5775  *
5776  * @return string error message, if no error empty string, if message
5777  */
5778  final public function unallocate($comment = "", $revision = true)
5779  {
5780  if ($this->allocated == 0) return "";
5781  $err = $this->canEdit();
5782  if ($err == "") {
5783  if ((!$this->withoutControl) && ($this->userid != $this->allocated)) $err = $this->control("unlock");
5784  }
5785 
5786  if ($err == "") {
5787  $u = new Account("", $this->allocated);
5788  if ($u->isAffected()) {
5789  $err = $this->unlock();
5790  if ($err == "") {
5791  $this->delUTag($this->userid, "AFFECTED"); // TODO need delete all AFFECTED tag
5792  if ($revision) $this->revise(sprintf(_("Unallocated of %s %s : %s") , $u->firstname, $u->lastname, $comment));
5793  else $this->addHistoryEntry(sprintf(_("Unallocated of %s %s: %s") , $u->firstname, $u->lastname, $comment));
5794  }
5795  } else {
5796  $err = _("user not know");
5797  }
5798  }
5799  if ($err == "") {
5800  $this->allocated = 0;
5801  $this->modify(true, array(
5802  "allocated"
5803  ) , true);
5804  $this->addLog('unallocate');
5805  }
5806 
5807  if ($err != "") $err = _("Unallocate aborded") . "\n" . $err;
5808  return $err;
5809  }
5810  /**
5811  * return icon url
5812  * if no icon found return doc.png
5813  * @param string $idicon
5814  * @param int $size width size
5815  * @return string icon url
5816  */
5817  final public function getIcon($idicon = "", $size = null, $otherId = null)
5818  {
5819  /*
5820  * @var Action $action
5821  */
5822  global $action;
5823  if ($idicon == "") $idicon = $this->icon;
5824  if ($idicon != "") {
5825 
5826  if (preg_match(PREGEXPFILE, $idicon, $reg)) {
5827  if ($idicon[0] === "!") {
5828  $efile = sprintf("file/%s/0/icon/-1/%s?inline=yes&width=%s", ($otherId == null) ? $this->id : $otherId, rawurlencode($reg["name"]) , $size);
5829  } elseif ($size) {
5830  $efile = "resizeimg.php?vid=" . $reg["vid"] . "&size=" . $size;
5831  } else {
5832  $efile = "FDL/geticon.php?vaultid=" . $reg["vid"] . "&mimetype=" . $reg["mime"];
5833  }
5834  } else {
5835  $efile = $action->parent->getImageLink($idicon, true, $size);
5836  }
5837  return $efile;
5838  } else {
5839  return $action->parent->getImageLink("doc.png", true, $size);
5840  }
5841  }
5842  /**
5843  * change icon for a class or a simple doc
5844  * @param string $icon basename icon file
5845  * @return string empty string on success, non-empty string on error
5846  */
5847  final public function changeIcon($icon)
5848  {
5849  $point = "dcp:changeIcon";
5850  if (($err = $this->savePoint($point)) != '') {
5851  return $err;
5852  }
5853 
5854  if (preg_match(PREGEXPFILE, $icon, $reg)) {
5855  $fileData = \Dcp\VaultManager::getFileInfo($reg["vid"]);
5856  if (!$fileData->public_access) {
5857  $icon = "!" . $icon;
5858  }
5859  }
5860 
5861  if ($this->doctype == "C") { // a class
5863  $tableName = sprintf("doc%s", $fromid);
5864  if ($this->icon != "") {
5865  // need disabled triggers to increase speed
5866  $qt = array();
5867  $qt[] = sprintf("ALTER TABLE %s DISABLE TRIGGER ALL", pg_escape_identifier($tableName));
5868  $qt[] = sprintf("UPDATE %s SET icon = %s WHERE (fromid = %s) AND (doctype != 'C') AND ((icon = %s) OR (icon IS NULL))", pg_escape_identifier($tableName) , pg_escape_literal($icon) , pg_escape_literal($fromid) , pg_escape_literal($this->icon));
5869  $qt[] = sprintf("ALTER TABLE %s ENABLE TRIGGER ALL", pg_escape_identifier($tableName));
5870  $qt[] = sprintf("UPDATE DOCREAD SET icon = %s WHERE (fromid = %s) AND (doctype != 'C') AND ((icon = %s) OR (icon IS NULL))", pg_escape_literal($icon) , pg_escape_literal($fromid) , pg_escape_literal($this->icon));
5871  if (($err = simpleQuery($this->dbaccess, implode("; ", $qt) , $res, false, false, false)) != '') {
5872  $this->rollbackPoint($point);
5873  return $err;
5874  }
5875  } else {
5876  $q = sprintf("UPDATE %s SET icon = %s WHERE (fromid = %s) AND (doctype != 'C') AND (icon IS NULL)", pg_escape_identifier($tableName) , pg_escape_literal($icon) , pg_escape_literal($fromid));
5877  if (($err = simpleQuery($this->dbaccess, $q, $res, false, false, false)) != '') {
5878  $this->rollbackPoint($point);
5879  return $err;
5880  }
5881  }
5882  }
5883  // $this->title = AddSlashes($this->title);
5884  $this->icon = $icon;
5885  if (($err = $this->Modify()) != '') {
5886  $this->rollbackPoint($point);
5887  return $err;
5888  }
5889  if (($err = $this->commitPoint($point)) != '') {
5890  $this->rollbackPoint($point);
5891  return $err;
5892  }
5893 
5894  $this->UpdateVaultIndex();
5895  return '';
5896  }
5897  /**
5898  * declare a dependance between several attributes
5899  * @param string $in attributes id use for compute $out attributes separates by commas
5900  * @param string $out attributes id calculated by $in attributes separates by commas
5901  */
5902  final public function addParamRefresh($in, $out)
5903  {
5904  // to know which attribut must be disabled in edit mode
5905  $tin = explode(",", strtolower($in));
5906  $tout = explode(",", strtolower($out));
5907  $this->paramRefresh["$in:$out"] = array(
5908  "in" => $tin,
5909  "out" => $tout
5910  );
5911  }
5912  /**
5913  * compute new visibility with depended attributes
5914  * @return array of visibilities computed with dependance between attributes
5915  */
5916  public function getRefreshVisibility()
5917  {
5918  $tv = array();
5919  foreach ($this->attributes->attr as $k => $v) {
5920  $tv[$v->id] = $v->mvisibility;
5921  }
5922  foreach ($this->paramRefresh as $k => $v) {
5923  $val = true;
5924  foreach ($v["in"] as $va) {
5925  $val = $this->getRawValue($va);
5926  if (!$val) {
5927  break;
5928  }
5929  }
5930  if ($val) {
5931  foreach ($v["out"] as $oa) {
5932  if (($tv[$oa] == "W") || ($tv[$oa] == "O")) $tv[$oa] = "S";
5933  }
5934  }
5935  }
5936 
5937  return $tv;
5938  }
5939  /**
5940  * Special Refresh
5941  * called when refresh document : when view, modify document - generally when access to the document
5942  * @note during preRefresh edit control is disabled
5943  * @see Doc::refresh
5944  * @api hook called in begining of refresh before update computed attributes
5945  */
5946  public function preRefresh()
5947  {
5948  return '';
5949  }
5950  /**
5951  * Special Refresh
5952  * called when refresh document : when view, modify document - generally when access to the document
5953  * @note during specRefresh edit control is disabled
5954  * @deprecated This hook may be replaced by preRefresh in the the next version.
5955  * @see Doc::refresh
5956  */
5957  public function specRefresh()
5958  {
5959  return '';
5960  }
5961  /**
5962  * post Refresh
5963  * called when refresh document : when view, modify document - generally when access to the document
5964  * a modify is done after if attributes are chahged
5965  * @note during postRefresh edit control is disabled
5966  * @see Doc::refresh
5967  * @api hook called at the end of refresh after update computed attributes
5968  */
5969  public function postRefresh()
5970  {
5971  return '';
5972  }
5973  /**
5974  * Special Refresh Generated automatically
5975  * is defined in generated child classes
5976  * @param bool $onlyspec
5977  * @return string
5978  */
5979  public function specRefreshGen(
5980  /* @noinspection PhpUnusedParameterInspection */
5981  $onlyspec = false)
5982  {
5983  return '';
5984  }
5985  /**
5986  * Special Refresh Generated for a single attribute
5987  * @param string $attrId Attribute's name
5988  * @param string $callMethod Method to apply
5989  * @return string Error message or empty string on succcess
5990  * @throws \Dcp\Exception
5991  */
5992  protected function specRefreshGenAttribute($attrId, $callMethod)
5993  {
5994  $err = '';
5995  $oAttr = $this->getAttribute($attrId);
5996  if (!$oAttr) throw new Dcp\Exception(ErrorCode::getError('ATTR1212', $callMethod, $this->fromname));
5997  if ($oAttr->mvisibility == 'I') {
5998  $this->log->warning(ErrorCode::getError('ATTR1800', $oAttr->id, $callMethod));
5999  } else {
6000  if ($oAttr->inArray()) {
6001  $this->completeArrayRow($oAttr->fieldSet->id);
6002  $t = $this->getMultipleRawValues($attrId);
6003  foreach ($t as $k => $v) {
6004  $err.= $this->setValue($attrId, $this->applyMethod($callMethod, '', $k) , $k);
6005  }
6006  } else {
6007  $err.= $this->setValue($attrId, $this->applyMethod($callMethod));
6008  }
6009  }
6010  return $err;
6011  }
6012  /**
6013  * recompute all computed attribut
6014  * and save the document in database if changes occurred
6015  * @api refresh document by calling specRefresh and update computed attributes
6016  * @return string information message
6017  */
6018  final public function refresh()
6019  {
6020  if ($this->locked == - 1) return ''; // no refresh revised document
6021  if (($this->doctype == 'C') || ($this->doctype == 'Z')) return ''; // no refresh for family and zombie document
6022  if ($this->lockdomainid > 0) return '';
6023  $changed = $this->hasChanged;
6024  if (!$changed) $this->disableEditControl(); // disabled control just to refresh
6025  $msg = $this->preRefresh();
6026  // if ($this->id == 0) return; // no refresh for no created document
6027  $msg.= $this->SpecRefreshGen();
6028  $msg.= $this->postRefresh();
6029  if ($this->hasChanged && $this->id > 0) {
6030  $this->lastRefreshError = $this->modify(); // refresh title
6031 
6032  }
6033  if (!$changed) $this->enableEditControl();
6034  return $msg;
6035  }
6036  /**
6037  * Recompute file name in concordance with rn option
6038  *
6039  */
6040  public function refreshRn()
6041  {
6042  $err = "";
6043  $fa = $this->GetFileAttributes();
6044  foreach ($fa as $aid => $oa) {
6045  $rn = $oa->getOption("rn");
6046  if ($rn) {
6047  if ($oa->inArray()) {
6048  $t = $this->getMultipleRawValues($oa->id);
6049  foreach ($t as $k => $v) {
6050  $cfname = $this->vault_filename($oa->id, false, $k);
6051  if ($cfname) {
6052  $fname = $this->applyMethod($rn, "", $k, array(
6053  $cfname
6054  ));
6055 
6056  if ($fname != $cfname) {
6057  $err.= $this->renameFile($oa->id, $fname, $k);
6058  }
6059  }
6060  }
6061  } else {
6062  $cfname = $this->vault_filename($oa->id);
6063  if ($cfname) {
6064  $fname = $this->applyMethod($rn, "", -1, array(
6065  $cfname
6066  ));
6067  if ($fname != $cfname) {
6068  $err.= $this->renameFile($oa->id, $fname);
6069  }
6070  }
6071  }
6072  }
6073  }
6074  return $err;
6075  }
6076  /**
6077  * replace % tag of a link attribute
6078  * @param string $link url to analyze
6079  * @param int $k index
6080  * @return bool|string
6081  */
6082  final public function urlWhatEncode($link, $k = - 1)
6083  {
6084  /*
6085  * @var Action $action
6086  */
6087  global $action;
6088 
6089  $urllink = "";
6090  $mi = strlen($link);
6091  for ($i = 0; $i < $mi; $i++) {
6092  switch ($link[$i]) {
6093  case '%':
6094  $i++;
6095 
6096  if (isset($link[$i]) && $link[$i] == "%") {
6097  $urllink.= "%"; // %% is %
6098 
6099  } else {
6100  $optional = false;
6101  if (isset($link[$i]) && $link[$i] == "?") {
6102  $i++;
6103  $optional = true;
6104  }
6105  if (isset($link[$i + 1]) && $link[$i + 1] == "%") {
6106  // special link
6107  switch ($link[$i]) {
6108  case "B": // baseurl
6109  $urllink.= $action->GetParam("CORE_BASEURL");
6110  break;
6111 
6112  case "S": // standurl
6113  $urllink.= $action->GetParam("CORE_STANDURL");
6114  break;
6115 
6116  case "U": // extern url
6117  $urllink.= $action->GetParam("CORE_EXTERNURL");
6118  break;
6119 
6120  case "I": // id
6121  $urllink.= $this->id;
6122  break;
6123 
6124  case "T": // title
6125  $urllink.= rawurlencode($this->title);
6126  break;
6127 
6128  default:
6129 
6130  break;
6131  }
6132  $i++; // skip end '%'
6133 
6134  } else {
6135 
6136  $sattrid = "";
6137  while (($i < $mi) && ($link[$i] != "%")) {
6138  $sattrid.= $link[$i];
6139  $i++;
6140  }
6141  if (preg_match('/^[a-z0-9_\\\\]*::/i', $sattrid)) {
6142  $mapArgs = array();
6143  foreach (self::$infofields as $propId => $prop) {
6144  $mapArgs[$propId] = $this->getPropertyValue($propId);
6145  }
6146  $urllink.= $this->applyMethod($sattrid, $sattrid, $k, array() , $mapArgs);
6147  } else {
6148 
6149  if (!in_array(mb_strtolower($sattrid) , $this->fields)) {
6150  if (preg_match('/[0-9A-F][0-9A-F]/', $sattrid)) {
6151  $urllink.= '%' . $sattrid; // hexa code
6152  if (isset($link[$i]) && $link[$i] == '%') {
6153  $urllink.= '%';
6154  }
6155  } else {
6156 
6157  if (!$optional) {
6158  return false;
6159  }
6160  }
6161  } else {
6162  /*
6163  * @var NormalAttribute $oa
6164  */
6165  $oa = $this->GetAttribute($sattrid);
6166  if (($k >= 0) && ($oa && $oa->repeat)) {
6167  $tval = $this->getMultipleRawValues($sattrid);
6168 
6169  $ovalue = isset($tval[$k]) ? chop($tval[$k]) : '';
6170  } else {
6171  // get property also
6172  $ovalue = $this->getRawValue($sattrid);
6173  }
6174  if ($ovalue == "" && (!$optional)) {
6175  return false;
6176  }
6177 
6178  if (strstr($ovalue, "\n")) {
6179  $ovalue = str_replace("\n", '\n', $ovalue);
6180  }
6181  $urllink.= rawurlencode($ovalue); // need encode
6182 
6183  }
6184  }
6185  }
6186  }
6187  break;
6188 
6189  case '{':
6190  $i++;
6191 
6192  $sattrid = "";
6193  while ($link[$i] != '}') {
6194  $sattrid.= $link[$i];
6195  $i++;
6196  }
6197  // print "attr=$sattrid";
6198  $ovalue = $action->getParam($sattrid);
6199  $urllink.= rawurlencode($ovalue);
6200 
6201  break;
6202 
6203  default:
6204  $urllink.= $link[$i];
6205  }
6206  }
6207  $urllink = $this->urlWhatEncodeSpec($urllink); // complete in special case families
6208  return (chop($urllink));
6209  }
6210  /**
6211  * virtual method must be use in child families if needed complete url
6212  * @param string $l url to encode
6213  * @return string
6214  */
6215  public function urlWhatEncodeSpec($l)
6216  {
6217  return $l;
6218  }
6219  /**
6220  * convert flat attribute value to an array for multiple attributes
6221  *
6222  * use only for specific purpose. If need typed attributes use Doc::getAttribute()
6223  * @api convert flat attribute value to an array
6224  * @see Doc::getAttributeValue
6225  * @param string $v value
6226  * @return array
6227  */
6228  public static function rawValueToArray($v)
6229  {
6230  if ($v === "" || $v === null) return array();
6231  return explode("\n", str_replace("\r", "", $v));
6232  }
6233  /**
6234  * convert flat attribute value to an array for multiple attributes
6235  * @deprecated use instead {@Doc::rawValueToArray}
6236  * @see Doc::rawValueToArray
6237  * @param string $v value
6238  * @return array
6239  */
6240  public static function _val2array($v)
6241  {
6243  return self::rawValueToArray($v);
6244  }
6245  /**
6246  * convert array value to flat attribute value
6247  * @api convert array value to flat attribute value
6248  * @param array $v
6249  * @param string $br
6250  * @return string
6251  */
6252  public static function arrayToRawValue($v, $br = '<BR>')
6253  {
6254  $v = str_replace("\n", $br, $v);
6255  if (count($v) == 0) return "";
6256  return implode("\n", $v);
6257  }
6258  /**
6259  * convert array value to flat attribute value
6260  * @param array $v
6261  * @param string $br
6262  * @deprecated use {@link Doc::arrayToRawValue} instead
6263  * @see Doc::arrayToRawValue
6264  * @return string
6265  */
6266  public static function _array2val($v, $br = '<BR>')
6267  {
6269  return self::arrayToRawValue($v, $br);
6270  }
6271  /**
6272  * return an url to access of folder/search RSS in open mode authentication
6273  * @return string the url anchor
6274  */
6275  public function getRssLink()
6276  {
6277  /*
6278  * @var Action $action
6279  */
6280  global $action;
6281  return sprintf("%s?app=FREEDOM&action=FREEDOM_RSS&dcpopen-authorization=%s&id=%s", $action->getParam("CORE_OPENURL", $action->getParam("CORE_EXTERNURL")) , $action->user->getUserToken(false, false, ["action" => "FREEDOM_RSS", "app" => "FREEDOM"]) , $this->id);
6282  }
6283  /**
6284  * return an url to download for file attribute
6285  * @param string $attrid attribute identifier
6286  * @param int $index set to row rank if it is in array else use -1
6287  * @param bool $cache set to true if file may be persistent in client cache
6288  * @param bool $inline set to true if file must be displayed in web browser
6289  * @param string $otherValue use another file value instead of attribute value
6290  * @param VaultFileInfo $info extra file info
6291  * @return string the url anchor
6292  */
6293  public function getFileLink($attrid, $index = - 1, $cache = false, $inline = false, $otherValue = '', $info = null)
6294  {
6295  if ($index === '' || $index === null) {
6296  $index = - 1;
6297  }
6298  if (!$otherValue) {
6299  if ($index >= 0) $avalue = $this->getMultipleRawValues($attrid, "", $index);
6300  else $avalue = $this->getRawValue($attrid);
6301  } else {
6302  if ($index >= 0) {
6303  if (is_array($otherValue)) $avalue = $otherValue[$index];
6304  else $avalue = $otherValue;
6305  } else $avalue = $otherValue;
6306  }
6307  $oa = $this->getAttribute($attrid);
6308  if ($oa->usefor === "Q" && $this->doctype !== "C") {
6310  } else {
6311  $docid = $this->id;
6312  }
6313 
6314  if (preg_match(PREGEXPFILE, $avalue, $reg)) {
6315  $fileKey = 0;
6316  if ($info) {
6317  $fileKey = strtotime($info->mdate);
6318  // Double quote not supported by all browsers - replace by minus
6319  $fname = str_replace('"', '-', $info->name);
6320  } else {
6321  $fname = str_replace('"', '-', $reg[3]);
6322  }
6323  // will be rewrited by apache rules
6324  //rewrite to "%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);
6325  $url = sprintf("file/%s/%d/%s/%s/%s?cache=%s&inline=%s", $docid, $fileKey, $attrid, $index, rawurlencode($fname) , $cache ? "yes" : "no", $inline ? "yes" : "no");
6326  if ($this->cvid > 0) {
6327  $viewId = getHttpVars("vid");
6328  if ($viewId) {
6329  $url.= '&cvViewid=' . $viewId;
6330  }
6331  }
6332  return $url;
6333  }
6334  return '';
6335  }
6336  /**
6337  * return an html anchor to a document
6338  * @api return an html anchor to a document
6339  * @param int $id identifier of document
6340  * @param string $target window target
6341  * @param bool $htmllink must be true else return nothing
6342  * @param bool|string $title should we override default title
6343  * @param bool $js should we add a javascript contextual menu
6344  * @param string $docrev style of link (default:latest, other values: fixed or state(xxx))
6345  * @param bool $viewIcon set to true to have icon in html link
6346  * @return string the html anchor
6347  */
6348  final public function getDocAnchor($id, $target = "_self", $htmllink = true, $title = false, $js = true, $docrev = "latest", $viewIcon = false)
6349  {
6350  $latest = ($docrev == "latest" || $docrev == "");
6351  if ($htmllink) {
6352  if (!$title) $title = $this->getHTMLTitle(strtok($id, '#') , '', $latest);
6353  else $title = $this->htmlEncode($title);
6354  if (trim($title) == "") {
6355  if ($id < 0) {
6356  $a = "<a>" . sprintf(_("document not exists yet")) . "</a>";
6357  } else {
6358  $a = "<a>" . sprintf(_("unknown document id %s") , $id) . "</a>";
6359  }
6360  } else {
6361  /* Setup base URL */
6362  $ul = '?';
6363  $specialUl = false;
6364  switch ($target) {
6365  case "mail":
6366  $js = false;
6367  $mUrl = getParam("CORE_MAILACTIONURL");
6368  if (strstr($mUrl, '%')) {
6369  if ($this->id != $id) {
6370  $mDoc = new_doc($this->dbaccess, $id);
6371  } else {
6372  $mDoc = $this;
6373  }
6374  $ul = htmlspecialchars($mDoc->urlWhatEncode($mUrl));
6375  $specialUl = true;
6376  } else {
6377  $ul = htmlspecialchars(GetParam("CORE_MAILACTIONURL"));
6378  $ul.= "&amp;id=$id";
6379  }
6380  break;
6381 
6382  case "ext":
6383  $ul.= "&amp;app=FDL&amp;action=VIEWEXTDOC&amp;id=$id";
6384  break;
6385 
6386  default:
6387  $ul.= "&amp;app=FDL&amp;action=OPENDOC&amp;mode=view&amp;id=$id";
6388  }
6389  /* Add target's specific elements to base URL */
6390  if ($target == "ext") {
6391  //$ec=getSessionValue("ext:targetRelation");
6392  $jslatest = ($latest) ? 'true' : 'false';
6393  $ec = getHttpVars("ext:targetRelation", 'Ext.fdl.Document.prototype.publish("opendocument",null,%V%,"view",{latest:' . $jslatest . '})');
6394  if ($ec) {
6395  if (!is_numeric($id)) $id = getIdFromName($this->dbaccess, $id);
6396  else if ($latest) {
6397  $lid = getLatestDocId($this->dbaccess, $id);
6398  if ($lid) $id = $lid;
6399  }
6400  $ec = str_replace("%V%", $id, $ec);
6401  $ecu = str_replace("'", '"', $ec);
6402  $ajs = "";
6403  if ($viewIcon) {
6404  simpleQuery($this->dbaccess, sprintf('select icon from docread where id=%d', $id) , $iconValue, true, true);
6405  $ajs.= sprintf('class="relation" style="background-image:url(%s)"', $this->getIcon($iconValue, 14));
6406  }
6407  $a = "<a $ajs onclick='parent.$ecu'>$title</a>";
6408  } else {
6409  if ($docrev == "latest" || $docrev == "" || !$docrev) $ul.= "&amp;latest=Y";
6410  elseif ($docrev != "fixed") {
6411  // validate that docrev looks like state(xxx)
6412  if (preg_match("/^state\\(([a-zA-Z0-9_:-]+)\\)/", $docrev, $matches)) {
6413  $ul.= "&amp;state=" . $matches[1];
6414  }
6415  }
6416  $a = "<a href=\"$ul\">$title</a>";
6417  }
6418  } else {
6419  if (!$specialUl) {
6420  if ($docrev == "latest" || $docrev == "" || !$docrev) {
6421  $ul.= "&amp;latest=Y";
6422  } elseif ($docrev != "fixed") {
6423  // validate that docrev looks like state(xxx)
6424  if (preg_match("/^state\\(([a-zA-Z0-9_:-]+)\\)/", $docrev, $matches)) {
6425  $ul.= "&amp;state=" . $matches[1];
6426  }
6427  }
6428  }
6429  if ($js) $ajs = "oncontextmenu=\"popdoc(event,'$ul');return false;\"";
6430  else $ajs = "";
6431 
6432  $ajs.= sprintf(' documentId="%s" ', $id);
6433  if ($viewIcon) {
6434  simpleQuery($this->dbaccess, sprintf('select icon from docread where id=%d', $id) , $iconValue, true, true);
6435  $ajs.= sprintf('class="relation" style="background-image:url(%s)"', $this->getIcon($iconValue, 14));
6436  }
6437  $a = "<a $ajs target=\"$target\" href=\"$ul\">$title</a>";
6438  }
6439  }
6440  } else {
6441  if (!$title) $a = $this->getHTMLTitle($id, '', $latest);
6442  else $a = $this->htmlEncode($title);
6443  }
6444  return $a;
6445  }
6446  /**
6447  * return HTML formated value of an attribute
6448  * @param NormalAttribute $oattr
6449  * @param string $value raw value
6450  * @param string $target html target in case of link
6451  * @param bool $htmllink
6452  * @param int $index
6453  * @param bool $entities
6454  * @param bool $abstract
6455  * @return string the formated value
6456  */
6457  final public function getHtmlValue($oattr, $value, $target = "_self", $htmllink = true, $index = - 1, $entities = true, $abstract = false)
6458  {
6459  if (!$this->htmlFormater) {
6460  $this->htmlFormater = new DocHtmlFormat($this);
6461  }
6462  if ($this->formaterLevel == 0) {
6463  $htmlFormater = & $this->htmlFormater;
6464  } else {
6465  if (!isset($this->otherFormatter[$this->formaterLevel])) {
6466  $this->otherFormatter[$this->formaterLevel] = new DocHtmlFormat($this);
6467  }
6468  $htmlFormater = $this->otherFormatter[$this->formaterLevel];
6469  }
6470  if ($htmlFormater->doc->id != $this->id) {
6471  $htmlFormater->setDoc($this);
6472  }
6473  $this->formaterLevel++;
6474  $r = $htmlFormater->getHtmlValue($oattr, $value, $target, $htmllink, $index, $entities, $abstract);
6475  $this->formaterLevel--;
6476  return $r;
6477  }
6478  /**
6479  * return an html anchor to a document
6480  * @see Doc::getHtmlValue
6481  * @param string $attrid attribute identifier
6482  * @param string $target html target in case of link
6483  * @param int $htmllink
6484  * @param $index
6485  * @param bool $entities
6486  * @param bool $abstract
6487  * @return string
6488  */
6489  final public function getHtmlAttrValue($attrid, $target = "_self", $htmllink = 2, $index = - 1, $entities = true, $abstract = false)
6490  {
6491  $oattr = $this->getAttribute($attrid);
6492  if (!$oattr) {
6493  throw new Dcp\Exception('DOC0130', $attrid, $this->id, $this->fromid);
6494  }
6495 
6496  if ($index != - 1) $v = $this->getMultipleRawValues($attrid, "", $index);
6497  else $v = $this->getRawValue($attrid);
6498 
6499  return $this->GetHtmlValue($oattr, $v, $target, $htmllink, $index, $entities, $abstract);
6500  }
6501  /**
6502  * Get a textual representation of the content of an attribute
6503  *
6504  * @param string $attrId logical name of the attr
6505  * @param $index
6506  * @param array $configuration value config array : dateFormat => 'US' 'ISO', decimalSeparator => '.',
6507  * multipleSeparator => array(0 => 'arrayLine', 1 => 'multiple') (defaultValue : dateFormat : 'US', decimalSeparator : '.', multiple => array(0 => "\n", 1 => ", "))
6508  *
6509  * @return string|bool return false if attribute not found else the textual value
6510  */
6511  final public function getTextualAttrValue($attrId, $index = - 1, Array $configuration = array())
6512  {
6513  $objectAttr = $this->getAttribute($attrId);
6514  if ($objectAttr) {
6515  return $objectAttr->getTextualValue($this, $index, $configuration);
6516  } else {
6517  return $objectAttr;
6518  }
6519  }
6520  /**
6521  * get value for open document text template
6522  * @param string $attrid attribute identifier
6523  * @param string $target unused
6524  * @param bool $htmllink unused
6525  * @param int $index index rank in case of multiple attribute value
6526  * @return string XML fragment
6527  */
6528  final public function getOooAttrValue($attrid,
6529  /* @noinspection PhpUnusedParameterInspection */
6530  $target = "_self",
6531  /* @noinspection PhpUnusedParameterInspection */
6532  $htmllink = false, $index = - 1)
6533  {
6534  if ($index != - 1) $v = $this->getMultipleRawValues($attrid, "", $index);
6535  else $v = $this->getRawValue($attrid);
6536  if ($v == "") return $v;
6537  return $this->getOooValue($this->getAttribute($attrid) , $v, '', false, $index);
6538  }
6539  /**
6540  * return open document text format for attribute value
6541  * @param NormalAttribute $oattr
6542  * @param string $value
6543  * @param string $target unused
6544  * @param bool $htmllink unused
6545  * @param int $index index rank in case of multiple attribute value
6546  * @return string XML fragment
6547  */
6548  final public function getOooValue($oattr, $value,
6549  /* @noinspection PhpUnusedParameterInspection */
6550  $target = "_self",
6551  /* @noinspection PhpUnusedParameterInspection */
6552  $htmllink = false, $index = - 1)
6553  {
6554 
6555  if (!$this->oooFormater) {
6556  $this->oooFormater = new DocOooFormat($this);
6557  }
6558  if ($this->oooFormater->doc->id != $this->id) {
6559  $this->oooFormater->setDoc($this);
6560  }
6561  return $this->oooFormater->getOooValue($oattr, $value, $index);
6562  }
6563  /**
6564  * Prevent displaying the document's title in the error message
6565  * if the user has no 'view' privilege
6566  *
6567  * @param Doc $doc
6568  * @param $aclname
6569  * @return string
6570  */
6571  protected function noPrivilegeMessage(Doc & $doc, $aclname)
6572  {
6573  /*
6574  * If the error message concerns the 'view' privilege, or the document
6575  * is confidential, or the user has no 'view' privilege on the
6576  * document, then we should not display the document's title
6577  */
6578  if (($aclname == 'view') || ($doc->isConfidential()) || ($doc->control('view') !== '')) {
6579  return sprintf(_("no privilege %s for document with id %d") , $aclname, $doc->id);
6580  }
6581  /*
6582  * Otherwise, display the error message with the document's title
6583  */
6584  return sprintf(_("no privilege %s for %s [%d]") , $aclname, $doc->getTitle() , $doc->id);
6585  }
6586  /**
6587  * Control Access privilege for document for current user
6588  *
6589  * @param string $aclname identifier of the privilege to test
6590  * @param bool $strict set tio true to test without notion of account susbstitute
6591  * @return string empty means access granted else it is an error message (access unavailable)
6592  */
6593  public function control($aclname, $strict = false)
6594  {
6595  if (!$this->isAffected()) {
6596  return '';
6597  }
6598  if (($this->profid <= 0) || ($this->userid == 1)) {
6599  return ""; // no profil or admin
6600 
6601  }
6602  $err = $this->controlId($this->profid, $aclname, $strict);
6603  if ($err != "") {
6604  return $this->noPrivilegeMessage($this, $aclname);
6605  } else {
6606  // Edit rights on profiles must also be controlled by the 'modifyacl' acl
6607  if (($aclname == 'edit' || $aclname == 'delete' || $aclname == 'unlock') && $this->isRealProfile()) {
6608  return $this->controlId($this->profid, 'modifyacl', $strict);
6609  }
6610  }
6611  return '';
6612  }
6613  /**
6614  * Control Access privilege for document for current user
6615  *
6616  * @api control document access
6617  * @param string $aclName identifier of the privilege to test
6618  * @param bool $strict set tio true to test without notion of account susbstitute
6619  * @return bool return true if access $aclName is granted, false else
6620  */
6621  public function hasPermission($aclName, $strict = false)
6622  {
6623  return ($this->control($aclName, $strict) == "");
6624  }
6625  /**
6626  * Control Access privilege for document for other user
6627  *
6628  * @param int $uid user identifier
6629  * @param string $aclname identifier of the privilege to test
6630  * @return string empty means access granted else it is an error message (access unavailable)
6631  */
6632  public function controlUser($uid, $aclname)
6633  {
6634  // --------------------------------------------------------------------
6635  if ($this->IsAffected()) {
6636  if (($this->profid <= 0) || ($uid == 1)) return ""; // no profil or admin
6637  if (!$uid) return _("control :: user identifier is null");
6638  return $this->controlUserId($this->profid, $uid, $aclname);
6639  }
6640  return "";
6641  }
6642  /**
6643  * verify that the document exists and is not in trash (not a zombie)
6644  * @api verify that the document exists and is not in trash
6645  * @return bool
6646  */
6647  final public function isAlive()
6648  {
6649  return ((DbObj::isAffected()) && ($this->doctype != 'Z'));
6650  }
6651  /**
6652  * add several triggers to update different tables (such as docread) or attributes (such as values)
6653  * @param bool $onlydrop set to false for only drop triggers
6654  * @param bool $code
6655  * @return string sql commands
6656  */
6657  final public function sqlTrigger($onlydrop = false, $code = false)
6658  {
6659 
6660  if (get_class($this) == "DocFam") {
6661  $cid = "fam";
6662  $famId = $this->id;
6663  } else {
6664  if ($this->doctype == 'C') return '';
6665  if (intval($this->fromid) == 0) return '';
6666 
6667  $cid = $this->fromid;
6669  }
6670 
6671  $sql = "";
6672  // delete all relative triggers
6673  $sql.= "select droptrigger('doc" . $cid . "');";
6674  if ($onlydrop) return $sql; // only drop
6675  if ($code) {
6676  $files = array();
6677  $lay = new Layout("FDL/sqltrigger.sql");
6678  $na = $this->GetNormalAttributes();
6679  $tvalues = array();
6680  $tsearch = array();
6681  $fulltext_c = array();
6682  foreach ($na as $k => $v) {
6683  $opt_searchcriteria = $v->getOption("searchcriteria", "");
6684  if (($v->type != "array") && ($v->type != "frame") && ($v->type != "tab")) {
6685  // values += any attribute
6686  if ($v->docid == $famId) {
6687  $tvalues[] = array(
6688  "attrid" => $k
6689  );
6690  }
6691  // svalues += attribute allowed to be indexed
6692  if (($v->type != "file") && ($v->type != "image") && ($v->type != "password") && ($opt_searchcriteria != "hidden")) {
6693 
6694  $tsearch[] = array(
6695  "attrid" => $k
6696  );
6697 
6698  $fulltext_c[] = array(
6699  "attrid" => $k
6700  );
6701  }
6702  }
6703  if ($v->type == "file" && $opt_searchcriteria != "hidden") {
6704  // fulltext += file attributes
6705  $files[] = array(
6706  "attrid" => $k . "_txt",
6707  "vecid" => $k . "_vec"
6708  );
6709  // svalues += file attributes
6710  $tsearch[] = array(
6711  "attrid" => $k . "_txt"
6712  );
6713  }
6714  }
6715  // fulltext += abstract attributes
6716  $tabstract = array();
6717  $na = $this->GetAbstractAttributes();
6718  foreach ($na as $k => $v) {
6719  $opt_searchcriteria = $v->getOption("searchcriteria", "");
6720  if ($opt_searchcriteria == "hidden") {
6721  continue;
6722  }
6723  if (($v->type != "array") && ($v->type != "file") && ($v->type != "image") && ($v->type != "password")) {
6724  $tabstract[] = array(
6725  "attrid" => $k
6726  );
6727  }
6728  }
6729  $lay->setBlockData("ATTRFIELD", $tvalues);
6730  $lay->setBlockData("SEARCHFIELD", $tsearch);
6731  $lay->setBlockData("ABSATTR", $tabstract);
6732  $lay->setBlockData("FILEATTR", $files);
6733  $lay->setBlockData("FILEATTR2", $files);
6734  $lay->setBlockData("FILEATTR3", $files);
6735  $lay->setBlockData("FULLTEXT_C", $fulltext_c);
6736  $lay->set("hasattr", (count($tvalues) > 0));
6737  $lay->set("hassattr", (count($tsearch) > 0));
6738  $lay->set("hasabsattr", (count($tabstract) > 0));
6739  $lay->set("docid", $this->fromid);
6740  $sql = $lay->gen();
6741  } else {
6742 
6743  if ($this->attributes !== null && isset($this->attributes->fromids) && is_array($this->attributes->fromids)) {
6744  foreach ($this->attributes->fromids as $k => $v) {
6745 
6746  $sql.= "create trigger UV{$cid}_$v BEFORE INSERT OR UPDATE ON doc$cid FOR EACH ROW EXECUTE PROCEDURE upval$v();";
6747  }
6748  }
6749  // the reset trigger must begin with 'A' letter to be proceed first (pgsql 7.3.2)
6750  if ($cid != "fam") {
6751  $sql.= "create trigger AUVR{$cid} BEFORE UPDATE ON doc$cid FOR EACH ROW EXECUTE PROCEDURE resetvalues();";
6752  $sql.= "create trigger VSEARCH{$cid} BEFORE INSERT OR UPDATE ON doc$cid FOR EACH ROW EXECUTE PROCEDURE searchvalues$cid();";
6753  } else {
6754  $sql.= "create trigger UVdocfam before insert or update on docfam FOR EACH ROW EXECUTE PROCEDURE upvaldocfam();";
6755  }
6756  $sql.= "create trigger zread{$cid} AFTER INSERT OR UPDATE OR DELETE ON doc$cid FOR EACH ROW EXECUTE PROCEDURE setread();";
6757  $sql.= "create trigger FIXDOC{$cid} AFTER INSERT ON doc$cid FOR EACH ROW EXECUTE PROCEDURE fixeddoc();";
6758  }
6759  return $sql;
6760  }
6761  /**
6762  * add specials SQL indexes
6763  *
6764  * @return array sqls queries to create indexes
6765  */
6766  final public function getSqlIndex()
6767  {
6768  $t = array();;
6769  $id = $this->fromid;
6770  if (static::$sqlindex) $sqlindex = array_merge(static::$sqlindex, Doc::$sqlindex);
6771  else $sqlindex = Doc::$sqlindex;
6772  foreach ($sqlindex as $k => $v) {
6773 
6774  if (!empty($v["unique"])) $unique = "unique";
6775  else $unique = "";
6776  if (!empty($v["using"])) {
6777 
6778  if ($v["using"][0] == "@") {
6779  $v["using"] = getParam(substr($v["using"], 1));
6780  }
6781  $t[] = sprintf("CREATE $unique INDEX %s$id on doc$id using %s(%s);\n", $k, $v["using"], $v["on"]);
6782  } else {
6783  $t[] = sprintf("CREATE $unique INDEX %s$id on doc$id(%s);\n", $k, $v["on"]);
6784  }
6785  }
6786  return $t;
6787  }
6788  /**
6789  * return the basename of template file
6790  * @param string $zone zone to parse
6791  * @return string|null (return null if template not found)
6792  */
6793  public function getZoneFile($zone)
6794  {
6795  $index = - 1;
6796  if ($zone == "") {
6797  return null;
6798  }
6799 
6800  $reg = $this->parseZone($zone);
6801  if (is_array($reg)) {
6802  $aid = $reg['layout'];
6803  if ($reg['index'] != '') {
6804  $index = $reg['index'];
6805  }
6806  $oa = $this->getAttribute($aid);
6807  if ($oa) {
6808  if ($oa->usefor != 'Q') {
6809  $template = $this->getRawValue($oa->id);
6810  } else {
6811  $template = $this->getFamilyParameterValue($aid);
6812  }
6813  if ($index >= 0) {
6814  $tt = $this->rawValueToArray($template);
6815  $template = $tt[$index];
6816  }
6817 
6818  if ($template == "") {
6819  return null;
6820  }
6821 
6822  return $this->vault_filename_fromvalue($template, true);
6823  }
6824  return getLayoutFile($reg['app'], ($aid));
6825  }
6826  return null;
6827  }
6828  /**
6829  * return the character in third part of zone
6830  * @param string $zone APP:LAYOUT:OPTIONS
6831  * @return string single character
6832  */
6833  public function getZoneOption($zone = "")
6834  {
6835  if ($zone == "") {
6836  $zone = $this->defaultview;
6837  }
6838 
6839  $zoneElements = $this->parseZone($zone);
6840  if ($zoneElements === false) {
6841  return '';
6842  }
6843 
6844  return $zoneElements['modifier'];
6845  }
6846  /**
6847  * return the characters in fourth part of zone
6848  * @param string $zone APP:LAYOUT:OPTIONS
6849  * @return string
6850  */
6851  public function getZoneTransform($zone = "")
6852  {
6853  if ($zone == "") {
6854  $zone = $this->defaultview;
6855  }
6856 
6857  $zoneElements = $this->parseZone($zone);
6858  if ($zoneElements === false) {
6859  return '';
6860  }
6861 
6862  return $zoneElements['transform'];
6863  }
6864  /**
6865  * set default values define in family document
6866  * the format of the string which define default values is like
6867  * [US_ROLE|director][US_SOCIETY|alwaysNet]...
6868  * @param array $tdefval the default values
6869  * @param bool $method set to false if don't want interpreted values
6870  * @param bool $forcedefault force default values
6871  * @throws \Dcp\Exception
6872  */
6873  final public function setDefaultValues($tdefval, $method = true, $forcedefault = false)
6874  {
6875  if (is_array($tdefval)) {
6876  foreach ($tdefval as $aid => $dval) {
6877  /*
6878  * @var BasicAttribute $oattr
6879  */
6880  $oattr = $this->getAttribute($aid);
6881 
6882  $ok = false;
6883  if (empty($oattr)) $ok = false;
6884  elseif ($dval === '' || $dval === null) $ok = false;
6885  elseif (!is_a($oattr, "BasicAttribute")) $ok = false;
6886  elseif ($forcedefault) $ok = true;
6887  elseif (!$oattr->inArray()) $ok = true;
6888  elseif ($oattr->fieldSet->format != "empty" && $oattr->fieldSet->getOption("empty") != "yes") {
6889  if (empty($tdefval[$oattr->fieldSet->id])) $ok = true;
6890  else $ok = false;
6891  }
6892  if ($ok) {
6893  if ($oattr->type == "array") {
6894  if ($method) {
6895 
6896  $values = json_decode($dval, true);
6897  if ($values === null) {
6898  $values = $this->applyMethod($dval, null);
6899  if ($values === null) {
6900  throw new Dcp\Exception("DFLT0007", $aid, $dval, $this->fromname);
6901  }
6902  }
6903  if (!is_array($values)) {
6904  throw new Dcp\Exception("DFLT0008", $aid, $dval, $values, $this->fromname);
6905  }
6906  $terr = [];
6907  foreach ($values as $row) {
6908  $err = $this->addArrayRow($aid, $row);
6909  if ($err) $terr[] = $err;
6910  }
6911  if ($terr) throw new Dcp\Exception("DFLT0009", $aid, $dval, $values, $this->fromname, implode('; ', $terr));
6912  }
6913  //print_r($this->getValues());
6914 
6915  } else {
6916  if ($method) {
6917  $this->setValue($aid, $this->GetValueMethod($dval));
6918  } else {
6919  $this->setValue($aid, $dval); // raw data
6920 
6921  }
6922  }
6923  } else {
6924  // TODO raise exception
6925 
6926  }
6927  }
6928  }
6929  }
6930  /**
6931  * set default name reference
6932  * if no name a new name will ne computed from its initid and family name
6933  * the new name is set to name attribute
6934  * @param boolean $temporary compute a temporary logical name that will be deleted by the cleanContext API
6935  * @return string error message (empty means OK).
6936  */
6937  final public function setNameAuto($temporary = false)
6938  {
6939  $err = '';
6940  if (($this->name == "") && ($this->initid > 0)) {
6941  $dfam = $this->getFamilyDocument();
6942  if ($dfam->name == "") return sprintf("no family name %s", $dfam->id);
6943  if ($temporary) {
6944  $this->name = sprintf('TEMPORARY_%s_%s_%s', $dfam->name, $this->initid, uniqid());
6945  } else {
6946  $this->name = $dfam->name . '_' . $this->initid;
6947  }
6948  $err = $this->modify(true, array(
6949  "name"
6950  ) , true);
6951  }
6952  return $err;
6953  }
6954  /**
6955  * Return the main path relation
6956  * list of prelid properties (primary relation)
6957  * the first item is the direct parent, the second:the grand-parent , etc.
6958  * @return array key=id , value=title of relation
6959  */
6960  function getMainPath()
6961  {
6962  $tr = array();
6963 
6964  if ($this->prelid > 0) {
6965 
6966  $d = getTDoc($this->dbaccess, $this->prelid);
6967  $fini = false;
6968  while (!$fini) {
6969  if ($d) {
6970  if (controlTDoc($d, "view")) {
6971  if (!in_array($d["initid"], array_keys($tr))) {
6972  $tr[$d["initid"]] = $d["title"];
6973  if ($d["prelid"] > 0) $d = getTDoc($this->dbaccess, $d["prelid"]);
6974  else $fini = true;
6975  } else $fini = true;
6976  } else $fini = true;
6977  } else {
6978  $fini = true;
6979  }
6980  }
6981  }
6982  return $tr;
6983  }
6984  /**
6985  * generate HTML code for view doc
6986  * @param string $layout layout to use to view document
6987  * @param string $target window target name for hyperlink destination
6988  * @param bool $ulink if false hyperlink are not generated
6989  * @param bool $abstract if true only abstract attribute are generated
6990  * @param bool $changelayout if true the internal layout ($this->lay) will be replace by the new layout
6991  * @throws Exception
6992  * @return string genererated template . If target is binary, return file path of temporary generated file
6993  */
6994  final public function viewDoc($layout = "FDL:VIEWBODYCARD", $target = "_self", $ulink = true, $abstract = false, $changelayout = false)
6995  {
6996  global $action;
6997 
6998  $reg = $this->parseZone($layout);
6999  if ($reg === false) {
7000  return htmlspecialchars(sprintf(_("error in pzone format %s") , $layout) , ENT_QUOTES);
7001  }
7002 
7003  if (array_key_exists('args', $reg)) {
7004  // in case of arguments in zone
7005  global $ZONE_ARGS;
7006  $layout = $reg['fulllayout'];
7007  if (array_key_exists('argv', $reg)) {
7008  foreach ($reg['argv'] as $k => $v) {
7009  $ZONE_ARGS[$k] = $v;
7010  }
7011  }
7012  }
7013  $play = null;
7014  if (!$changelayout) {
7015  $play = $this->lay;
7016  }
7017  $binary = ($this->getZoneOption($layout) == "B");
7018 
7019  $tplfile = $this->getZoneFile($layout);
7020 
7021  $ext = getFileExtension($tplfile);
7022  if (strtolower($ext) == "odt") {
7023  include_once ('Class.OOoLayout.php');
7024  $target = "ooo";
7025  $ulink = false;
7026  $this->lay = new OOoLayout($tplfile, $action, $this);
7027  } else {
7028  $this->lay = new Layout($tplfile, $action, "");
7029  }
7030  //if (! file_exists($this->lay->file)) return sprintf(_("template file (layout [%s]) not found"), $layout);
7031  $this->lay->set("_readonly", ($this->Control('edit') != ""));
7032  $method = strtok(strtolower($reg['layout']) , '.');
7033  if (method_exists($this, $method)) {
7034  try {
7035  $refMeth = new ReflectionMethod(get_class($this) , $method);
7036  if (preg_match('/@templateController\b/', $refMeth->getDocComment())) {
7037  $this->$method($target, $ulink, $abstract);
7038  } else {
7039  global $action;
7040  $syserr = ErrorCode::getError("DOC1101", $refMeth->getDeclaringClass()->getName() , $refMeth->getName() , $this);
7041  $action->log->error($syserr);
7042  $err = htmlspecialchars(sprintf(_("Layout \"%s\" : Controller not allowed") , $layout) , ENT_QUOTES);
7043  return $err;
7044  }
7045  }
7046  catch(Exception $e) {
7047  if ((!file_exists($this->lay->file) && (!$this->lay->template))) {
7048  return htmlspecialchars(sprintf(_("template file (layout [%s]) not found") . ": %s", $layout, $e->getMessage()) , ENT_QUOTES);
7049  } else {
7050  throw $e;
7051  }
7052  }
7053  } else {
7054  $this->viewdefaultcard($target, $ulink, $abstract);
7055  }
7056 
7057  if ((!file_exists($this->lay->file) && (!$this->lay->template))) {
7058  return htmlspecialchars(sprintf(_("template file (layout [%s]) not found") , $layout) , ENT_QUOTES);
7059  }
7060 
7061  $laygen = $this->lay->gen();
7062 
7063  if (!$changelayout) $this->lay = $play;
7064 
7065  if (!$ulink) {
7066  // suppress href attributes
7067  return preg_replace(array(
7068  "/href=\"index\\.php[^\"]*\"/i",
7069  "/onclick=\"[^\"]*\"/i",
7070  "/ondblclick=\"[^\"]*\"/i"
7071  ) , array(
7072  "",
7073  "",
7074  ""
7075  ) , $laygen);
7076  }
7077  if ($target == "mail") {
7078  // suppress session id
7079  return preg_replace("/\\?session=[^&]*&/", "?", $laygen);
7080  }
7081  if ($binary && ($target != "ooo")) {
7082  // set result into file
7083  $tmpfile = uniqid(getTmpDir() . "/fdllay") . ".html";
7084  file_put_contents($tmpfile, $laygen);
7085  $laygen = $tmpfile;
7086  }
7087 
7088  return $laygen;
7089  }
7090  /**
7091  * default construct layout for view card containt
7092  *
7093  * @templateController default controller view
7094  * @param string $target window target name for hyperlink destination
7095  * @param bool $ulink if false hyperlink are not generated
7096  * @param bool $abstract if true only abstract attribute are generated
7097  * @param bool $viewhidden if true view also hidden attributes
7098  */
7099  final public function viewdefaultcard($target = "_self", $ulink = true, $abstract = false, $viewhidden = false)
7100  {
7101  $this->viewattr($target, $ulink, $abstract, $viewhidden);
7102  $this->viewprop($target, $ulink, $abstract);
7103  }
7104  /**
7105  * construct layout for view card containt
7106  *
7107  * @templateController default HTML view controller
7108  * @param string $target window target name for hyperlink destination
7109  * @param bool $ulink if false hyperlink are not generated
7110  * @param bool $abstract if true only abstract attribute are generated
7111  * @param bool $onlyopt if true only optional attributes are displayed
7112  * @throws \Dcp\Exception
7113  */
7114  function viewbodycard($target = "_self", $ulink = true, $abstract = false, $onlyopt = false)
7115  {
7116  /*
7117  * @var Action $action
7118  */
7119  global $action;
7120 
7121  $frames = array();
7122  if ($abstract) {
7123  // only 3 properties for abstract mode
7124  $listattr = $this->GetAbstractAttributes();
7125  } else {
7126  $listattr = $this->GetNormalAttributes($onlyopt);
7127  }
7128 
7129  $k = 0; // number of frametext
7130  $v = 0; // number of value in one frametext
7131  $nbimg = 0; // number of image in one frametext
7132  $currentFrameId = "";
7133  /**
7134  * @var FieldSetAttribute
7135  */
7136  $currentFrame = null;
7137  $changeframe = false; // is true when need change frame
7138  $tableframe = array();
7139  $tableimage = array();
7140  $ttabs = array();
7141  $frametpl = '';
7142 
7143  $iattr = 0;
7144  $onlytab = strtolower(getHttpVars("onlytab"));
7145  $tabonfly = false; // I want tab on fly
7146  $showonlytab = ($onlytab ? $onlytab : false);
7147  if ($onlytab) {
7148  $this->addUTag($this->userid, "lasttab", $onlytab);
7149  }
7150  /*
7151  * @var NormalAttribute $attr
7152  */
7153  foreach ($listattr as $i => $attr) {
7154  if ($onlytab && ($attr->fieldSet->id != $onlytab && $attr->fieldSet->fieldSet->id != $onlytab)) continue;
7155 
7156  $iattr++;
7157  $htmlvalue = '';
7158  //------------------------------
7159  // Compute value element
7160  $value = chop($this->getRawValue($i));
7161  if (!$attr->fieldSet) {
7162  addWarningMsg(sprintf(_("unknow set for attribute %s %s") , $attr->id, $attr->getLabel()));
7163  continue;
7164  }
7165  $frametpl = $attr->fieldSet->getOption("viewtemplate");
7166  if ($attr->fieldSet && ($frametpl && $attr->fieldSet->type != "array")) {
7167  $goodvalue = false;
7168  if ($currentFrameId != $attr->fieldSet->id) {
7169  if (($currentFrameId != "") && ($attr->fieldSet->mvisibility != "H") && ($attr->fieldSet->mvisibility != "I")) {
7170  $changeframe = true;
7171  }
7172  }
7173  } else {
7174  $goodvalue = ((($value != "") || ($attr->type == "array") || $attr->getOption("showempty")) && ($attr->mvisibility != "H") && ($attr->mvisibility != "I") && ($attr->mvisibility != "O") && (!$attr->inArray()));
7175  if (($attr->type == "array") && (!$attr->getOption("showempty"))) {
7176  if (count($this->getArrayRawValues($attr->id)) == 0) $goodvalue = false;
7177  }
7178 
7179  if ($goodvalue) {
7180  // detect first tab
7181  $toptab = $attr->getTab();
7182  /*
7183  * @var FieldsetAttribute $toptab
7184  */
7185  if ($toptab) $tabonfly = ($toptab->getOption("viewonfly") == "yes");
7186  if ($tabonfly && (!$showonlytab)) {
7187  $ut = $this->getUtag("lasttab");
7188  if ($ut) $showonlytab = $ut->comment;
7189  elseif ($attr->fieldSet->id && $attr->fieldSet->fieldSet) {
7190  $showonlytab = $attr->fieldSet->fieldSet->id;
7191  }
7192  }
7193  $attrInNextTab = ($tabonfly && $toptab && ($toptab->id != $showonlytab));
7194  if (!$attrInNextTab) {
7195  $viewtpl = $attr->getOption("viewtemplate");
7196  if ($viewtpl) {
7197  if ($viewtpl == "none") {
7198  $htmlvalue = '';
7199  } else {
7200  if ($this->getZoneOption($viewtpl) == 'S') {
7201  $attr->setOption("vlabel", "none");
7202  }
7203  $htmlvalue = sprintf("[ZONE FDL:VIEWTPL?id=%d&famid=%d&target=%s&zone=%s]", $this->id, $this->fromid, $target, $viewtpl);
7204  }
7205  } else {
7206  $htmlvalue = $this->GetHtmlValue($attr, $value, $target, $ulink);
7207  }
7208  } else {
7209  $htmlvalue = false; // display defer
7210 
7211  }
7212  } else $htmlvalue = "";
7213 
7214  if (($htmlvalue === false) || ($goodvalue)) { // to define when change frame
7215  if ($currentFrameId != $attr->fieldSet->id) {
7216  if (($currentFrameId != "") && ($attr->fieldSet->mvisibility != "H")) $changeframe = true;
7217  }
7218  }
7219  }
7220  //------------------------------
7221  // change frame if needed
7222  if ($changeframe) { // to generate fieldset
7223  if ($currentFrameId == '') {
7224  throw new Dcp\Exception('DOC0124', $attr->id);
7225  }
7226  $oaf = $this->getAttribute($currentFrameId);
7227  if (!is_object($oaf)) {
7228  throw new Dcp\Exception('DOC0125', $currentFrameId, $attr->id);
7229  }
7230  $frametpl = $oaf->getOption("viewtemplate");
7231  $changeframe = false;
7232  if ((($v + $nbimg) > 0) || $frametpl) { // one value detected
7233  $frames[$k]["frametext"] = ($oaf && $oaf->getOption("vlabel") != "none") ? mb_ucfirst($this->GetLabel($oaf->id)) : "";
7234  $frames[$k]["frameid"] = $oaf->id;
7235  $frames[$k]["bgcolor"] = $oaf ? $oaf->getOption("bgcolor", false) : false;
7236 
7237  $frames[$k]["tag"] = "";
7238  $frames[$k]["TAB"] = false;
7239  /*
7240  * @var FieldSetAttribute $pSet
7241  */
7242  $pSet = $oaf->fieldSet;
7243  if ($pSet && ($pSet->id != "") && ($pSet->id != Adoc::HIDDENFIELD)) {
7244  $frames[$k]["tag"] = "TAG" . $pSet->id;
7245  $frames[$k]["TAB"] = true;
7246  $ttabs[$pSet->id] = array(
7247  "tabid" => $pSet->id,
7248  "tabtitle" => ($pSet->getOption("vlabel") == "none") ? '&nbsp;' : mb_ucfirst($pSet->getLabel())
7249  );
7250  }
7251  $frames[$k]["viewtpl"] = ($frametpl != "");
7252  $frames[$k]["zonetpl"] = ($frametpl != "") ? sprintf("[ZONE FDL:VIEWTPL?id=%d&famid=%d&target=%s&zone=%s]", $this->id, $this->fromid, $target, $frametpl) : '';
7253 
7254  $frames[$k]["rowspan"] = $v + 1; // for images cell
7255  $frames[$k]["TABLEVALUE"] = "TABLEVALUE_$k";
7256 
7257  $this->lay->SetBlockData($frames[$k]["TABLEVALUE"], $tableframe);
7258  $frames[$k]["IMAGES"] = "IMAGES_$k";
7259  $this->lay->SetBlockData($frames[$k]["IMAGES"], $tableimage);
7260  $frames[$k]["notloaded"] = false;
7261  if ($oaf && $oaf->type == "frame" && (count($tableframe) + count($tableimage)) == 0) {
7262  if (!$frames[$k]["viewtpl"]) {
7263  $frames[$k]["viewtpl"] = true;
7264  $frames[$k]["zonetpl"] = _("Loading...");
7265  $frames[$k]["notloaded"] = true;
7266  }
7267  }
7268  unset($tableframe);
7269  unset($tableimage);
7270  $tableframe = array();
7271  $tableimage = array();
7272  $k++;
7273  }
7274  $v = 0;
7275  $nbimg = 0;
7276  $currentFrameId = $attr->fieldSet->id;
7277  }
7278  if ($htmlvalue === false) {
7279  $goodvalue = false;
7280  if ($currentFrameId != $attr->fieldSet->id) {
7281  if (($attr->fieldSet->mvisibility != "H") && ($attr->fieldSet->mvisibility != "I")) {
7282  $changeframe = true;
7283  $currentFrameId = $attr->fieldSet->id;
7284  $currentFrame = $attr->fieldSet;
7285  $v++;
7286  }
7287  }
7288  }
7289  //------------------------------
7290  // Set the table value elements
7291  if ($goodvalue) {
7292  switch ($attr->type) {
7293  case "image":
7294  $tableimage[$nbimg]["imgsrc"] = $htmlvalue;
7295  $tableimage[$nbimg]["itarget"] = ($action->Read("navigator", "") == "NETSCAPE") ? "_self" : "_blank";
7296  $width = $attr->getOption("iwidth", "80px");
7297  $tableimage[$nbimg]["imgwidth"] = $width;
7298  if (strstr($htmlvalue, 'EXPORTFILE')) {
7299  $tableimage[$nbimg]["imgthumbsrc"] = $htmlvalue . "&width=" . intval($width);
7300  } else {
7301  $tableimage[$nbimg]["imgthumbsrc"] = $htmlvalue;
7302  }
7303  break;
7304 
7305  default:
7306  $tableframe[$v]["nonelabel"] = false;
7307  $tableframe[$v]["normallabel"] = true;
7308  $tableframe[$v]["uplabel"] = false;
7309  $tableframe[$v]["value"] = $htmlvalue;
7310  break;
7311  }
7312 
7313  if (($attr->fieldSet->mvisibility != "H") && ($htmlvalue !== "" || $goodvalue)) {
7314  $currentFrameId = $attr->fieldSet->id;
7315  $currentFrame = $attr->fieldSet;
7316  }
7317  // print name except image (printed otherthere)
7318  if ($attr->type != "image") {
7319  $tableframe[$v]["wvalue"] = (($attr->type == "array") && ($attr->getOption("vlabel") == "up" || $attr->getOption("vlabel") == "none")) ? "1%" : "30%"; // width
7320  $tableframe[$v]["ndisplay"] = "inline";
7321 
7322  if ($attr->getOption("vlabel") == "none") {
7323  $tableframe[$v]["nonelabel"] = true;
7324  $tableframe[$v]["normallabel"] = false;
7325  } else if ($attr->getOption("vlabel") == "up") {
7326  if ($attr->type == "array") { // view like none label
7327  $tableframe[$v]["nonelabel"] = true;
7328  $tableframe[$v]["normallabel"] = false;
7329  } else {
7330  $tableframe[$v]["normallabel"] = false;
7331  $tableframe[$v]["uplabel"] = true;
7332  }
7333  }
7334  $tableframe[$v]["name"] = $this->GetLabel($attr->id);
7335  if (($attr->type == "htmltext") && (count($tableframe) == 1)) {
7336  $keys = array_keys($listattr);
7337  if (isset($keys[$iattr])) {
7338  $na = $listattr[$keys[$iattr]]; // next attribute
7339  if ($na->fieldSet->id != $attr->fieldSet->id) { // only when only one attribute in frame
7340  $tableframe[$v]["ndisplay"] = "none";
7341  $tableframe[$v]["wvalue"] = "1%";
7342  }
7343  }
7344  }
7345 
7346  $tableframe[$v]["attrid"] = $attr->id;
7347  $tableframe[$v]["atype"] = $attr->type;
7348  $tableframe[$v]["classback"] = ($attr->usefor == "O") ? "FREEDOMOpt" : "FREEDOMBack1";
7349  $v++;
7350  } else {
7351  $tableimage[$nbimg]["imgalt"] = $this->GetLabel($attr->id);
7352  $nbimg++;
7353  }
7354  }
7355  if ($currentFrameId == '' && isset($attr->fieldSet->id)) {
7356  $currentFrameId = $attr->fieldSet->id;
7357  }
7358  }
7359  $oaf = $this->getAttribute($currentFrameId);
7360  if ($oaf) {
7361  $frametpl = $oaf->getOption("viewtemplate");
7362  }
7363  if ((($v + $nbimg) > 0) || $frametpl) // // last fieldset
7364  {
7365  if ($oaf) $frames[$k]["frametext"] = ($oaf->getOption("vlabel") != "none") ? mb_ucfirst($this->GetLabel($currentFrameId)) : "";
7366  else $frames[$k]["frametext"] = '';
7367  $frames[$k]["frameid"] = $currentFrameId;
7368  $frames[$k]["tag"] = "";
7369  $frames[$k]["TAB"] = false;
7370  $frames[$k]["viewtpl"] = ($frametpl != "");
7371  $frames[$k]["zonetpl"] = ($frametpl != "") ? sprintf("[ZONE FDL:VIEWTPL?id=%d&famid=%d&target=%s&zone=%s]", $this->id, $this->fromid, $target, $frametpl) : '';
7372 
7373  $frames[$k]["bgcolor"] = $oaf ? $oaf->getOption("bgcolor", false) : false;
7374  $pSet = (isset($currentFrame->fieldSet) ? $currentFrame->fieldSet : null);
7375  if ($pSet !== null && ($pSet->id != "") && ($pSet->id != Adoc::HIDDENFIELD)) {
7376  $frames[$k]["tag"] = "TAG" . $pSet->id;
7377  $frames[$k]["TAB"] = true;
7378  $ttabs[$pSet->id] = array(
7379  "tabid" => $pSet->id,
7380  "tabtitle" => ($pSet->getOption("vlabel") == "none") ? '&nbsp;' : mb_ucfirst($pSet->getLabel())
7381  );
7382  }
7383  $frames[$k]["rowspan"] = $v + 1; // for images cell
7384  $frames[$k]["TABLEVALUE"] = "TABLEVALUE_$k";
7385 
7386  $this->lay->SetBlockData($frames[$k]["TABLEVALUE"], $tableframe);
7387 
7388  $frames[$k]["IMAGES"] = "IMAGES_$k";
7389  $this->lay->SetBlockData($frames[$k]["IMAGES"], $tableimage);
7390  $frames[$k]["notloaded"] = false;
7391  if ($oaf->type == "frame" && (count($tableframe) + count($tableimage)) == 0) {
7392  if (!$frames[$k]["viewtpl"]) {
7393  $frames[$k]["viewtpl"] = true;
7394  $frames[$k]["zonetpl"] = _("Loading...");
7395  $frames[$k]["notloaded"] = true;
7396  }
7397  }
7398  }
7399  // Out
7400  $this->lay->SetBlockData("TABLEBODY", $frames);
7401  $this->lay->SetBlockData("TABS", $ttabs);
7402  $this->lay->Set("ONETAB", count($ttabs) > 0);
7403  $this->lay->Set("NOTAB", ($target == "mail") || $onlytab);
7404  $this->lay->Set("docid", $this->id);
7405 
7406  if (count($ttabs) > 0) {
7407  $this->lay->Set("firsttab", false);
7408  $ut = $this->getUtag("lasttab");
7409  if ($ut) $firstopen = $ut->comment; // last memo tab
7410  else $firstopen = false;
7411  foreach ($ttabs as $k => $v) {
7412  $oa = $this->getAttribute($k);
7413  if ($oa->getOption("firstopen") == "yes") $this->lay->set("firsttab", $k);
7414  if ($firstopen == $oa->id) $this->lay->Set("firsttab", $k);
7415  }
7416  }
7417  }
7418  /**
7419  * write layout for thumb view
7420  * @templateController controller for thumb view (used in mail link)
7421  * @param string $target
7422  * @param bool $ulink
7423  * @param bool $abstract
7424  */
7425  function viewthumbcard($target = "finfo", $ulink = true, $abstract = true)
7426  {
7427  $this->viewabstractcard($target, $ulink, $abstract);
7428  $this->viewprop($target, $ulink, $abstract);
7429  $this->lay->set("iconsrc", $this->getIcon());
7430  $this->lay->set("TITLE", $this->getHTMLTitle());
7431  $state = $this->getState();
7432  if ($state != "") $this->lay->set("state", _($state));
7433  else $this->lay->set("state", "");
7434  }
7435  /**
7436  * layout for view answers
7437  * @templateController controller used if use WASK in workflow
7438  */
7439  function viewanswers( /*$target = "finfo", $ulink = true, $abstract = true*/)
7440  {
7441  $err = '';
7442  if (!$this->isAlive()) $err = (sprintf(_("unknow document reference '%s'") , GetHttpVars("docid")));
7443  if ($err == "") $err = $this->control("wask");
7444  if ($err) {
7445  $this->lay->template = $err;
7446  $this->lay->noparse = true;
7447  return;
7448  }
7449 
7450  $answers = $this->getWasks(false);
7451  $tw = array();
7452  foreach ($answers as $ka => $ans) {
7453  $utags = $this->searchUTags("ASK_" . $ans["waskid"], false, true);
7454  /**
7455  * @var \Dcp\Family\WASK $wask
7456  */
7457  $wask = new_doc($this->dbaccess, $ans["waskid"]);
7458  $wask->set($this);
7459 
7460  $taguid = array();
7461 
7462  $t = array();
7463  foreach ($utags as $k => $v) {
7464  $taguid[] = $v["uid"];
7465  $t[$k] = $v;
7466  $t[$k]["label"] = $wask->getAskLabel($v["comment"]);
7467  $t[$k]["ask"] = $wask->getRawValue("was_ask");
7468  }
7469 
7470  uasort($t, array(
7471  get_class($this) ,
7472  "_cmpanswers"
7473  ));
7474  $prevc = '';
7475  $odd = 0;
7476  foreach ($t as $k => $v) {
7477  if ($v["comment"] != $prevc) {
7478  $prevc = $v["comment"];
7479  $odd++;
7480  }
7481  $t[$k]["class"] = (($odd % 2) == 0) ? "evenanswer" : "oddanswer";
7482  }
7483  // find user not answered
7484  $ru = $wask->getUsersForAcl('answer'); // all users must answered
7485  $una = array_diff(array_keys($ru) , $taguid);
7486 
7487  $tna = array();
7488 
7489  $tuna = array();
7490  foreach ($una as $k => $v) {
7491  $tuna[$v] = $ru[$v]["login"];
7492  }
7493 
7494  asort($tuna, SORT_STRING);
7495  foreach ($tuna as $k => $v) {
7496  $tna[] = array(
7497  "login" => $ru[$k]["login"],
7498  "fn" => $ru[$k]["firstname"],
7499  "ln" => $ru[$k]["lastname"]
7500  );
7501  }
7502 
7503  $this->lay->setBlockData("ANSWERS" . $wask->id, $t);
7504  $this->lay->setBlockData("NOTANS" . $wask->id, $tna);
7505  $title = $wask->getTitle();
7506 
7507  $this->lay->set("asktitle", $title);
7508  $tw[] = array(
7509  "waskid" => $wask->id,
7510  "nacount" => sprintf(_("number of waiting answers %d") , count($una)) ,
7511  "count" => (count($t) > 1) ? sprintf(_("%d answers") , count($t)) : sprintf(_("%d answer") , count($t)) ,
7512  "ask" => $wask->getRawValue("was_ask")
7513  );
7514  }
7515  $this->lay->setBlockData("WASK", $tw);
7516  $this->lay->set("docid", $this->id);
7517  }
7518  /**
7519  * to sort answer by response
7520  * @param string $a
7521  * @param string $b
7522  * @return int
7523  */
7524  static function _cmpanswers($a, $b)
7525  {
7526  return strcasecmp($a["comment"] . $a["uname"], $b["comment"] . $b["uname"]);
7527  }
7528  /**
7529  * @templateController controller to view document properties
7530  * write layout for properties view
7531  * @param string $target
7532  * @param bool $ulink
7533  * @param bool $abstract
7534  */
7535  function viewproperties($target = "finfo", $ulink = true, $abstract = true)
7536  {
7537  global $action;
7538  $this->viewprop($target, $ulink, $abstract);
7539  $this->lay->eSet("iconsrc", $this->getIcon());
7540  $fdoc = $this->getFamilyDocument();
7541  $this->lay->eSet("ficonsrc", $fdoc->getIcon());
7542  $owner = new Account("", abs($this->owner));
7543  $this->lay->rSet("username", str_replace(array(
7544  '[',
7545  ']'
7546  ) , array(
7547  '&#91;',
7548  '&#93;'
7549  ) , htmlspecialchars($owner->firstname . " " . $owner->lastname)));
7550  $this->lay->rSet("userid", $owner->fid);
7551  $this->lay->rSet("lockedby", $this->lay->get("locked"));
7552 
7553  $this->lay->rSet("lockdomain", '');
7554  if ($this->locked == - 1) {
7555  $this->lay->rSet("lockedid", false);
7556  } else {
7557  $user = new Account("", abs($this->locked));
7558  // $this->lay->Set("locked", $user->firstname." ".$user->lastname);
7559  if ($this->lockdomainid) {
7560  $this->lay->eSet("lockdomain", sprintf(_("in domain %s") , $this->getDocAnchor($this->lockdomainid, '_blank', true, '', false, true, true)));
7561  }
7562  $this->lay->rSet("lockedid", $user->fid);
7563  }
7564  $state = $this->getState();
7565  if ($state != "") {
7566  if (($this->locked == - 1) || ($this->lmodify != 'Y')) $this->lay->eSet("state", _($state));
7567  else $this->lay->rSet("state", sprintf(_("current (<em>%s</em>)") , htmlspecialchars(_($state) , ENT_QUOTES)));
7568  } else $this->lay->eset("state", _("no state"));
7569  if (is_numeric($this->state) && ($this->state > 0) && (!$this->wid)) {
7570  $this->lay->rSet("freestate", $this->state);
7571  } else $this->lay->rSet("freestate", false);
7572  $this->lay->rSet("setname", (bool)$action->parent->Haspermission("FREEDOM_MASTER", "FREEDOM"));
7573  $this->lay->rSet("lname", $this->name);
7574  $this->lay->rSet("hasrevision", ($this->revision > 0));
7575  $this->lay->eSet("moddate", strftime("%Y-%m-%d %H:%M:%S", $this->revdate));
7576  $this->lay->eSet("moddatelabel", _("last modification date"));
7577  if ($this->locked == - 1) {
7578  if ($this->doctype == 'Z') $this->lay->eSet("moddatelabel", _("suppression date"));
7579  else $this->lay->eSet("moddatelabel", _("revision date"));
7580  }
7581  if (GetParam("CORE_LANG") == "fr_FR") { // date format depend of locale
7582  $this->lay->eSet("revdate", strftime("%a %d %b %Y %H:%M", $this->revdate));
7583  } else {
7584  $this->lay->eSet("revdate", strftime("%x %T", $this->revdate));
7585  }
7586  $this->lay->eSet("version", $this->version);
7587 
7588  if ((abs($this->profid) > 0) && ($this->profid != $this->id)) {
7589 
7590  $this->lay->rSet("profile", $this->getDocAnchor(abs($this->profid) , '_blank', true, '', false, 'latest', true));
7591  } else {
7592  if ($this->profid == 0) {
7593  $this->lay->eSet("profile", _("no access control"));
7594  } else {
7595  if ($this->dprofid == 0) {
7596 
7597  $this->lay->rSet("profile", $this->getDocAnchor(abs($this->profid) , '_blank', true, _("specific control") , false, 'latest', true));
7598  } else {
7599  $this->lay->rSet("profile", $this->getDocAnchor(abs($this->dprofid) , '_blank', true, _("dynamic control") . " (" . $this->getTitle(abs($this->dprofid)) . ")", false, 'latest', true));
7600  }
7601  }
7602  }
7603  if ($this->cvid == 0) {
7604  $this->lay->eSet("cview", _("no view control"));
7605  } else {
7606  $this->lay->rSet("cview", $this->getDocAnchor($this->cvid, '_blank', true, '', false, 'latest', true));
7607  }
7608  if ($this->prelid == 0) {
7609  $this->lay->eSet("prel", _("no folder"));
7610  } else {
7611 
7612  $this->lay->rSet("prel", $this->getDocAnchor($this->prelid, '_blank', true, '', false, 'latest', true));
7613  $fldids = $this->getParentFolderIds();
7614  $tfld = array();
7615  foreach ($fldids as $fldid) {
7616  if ($fldid != $this->prelid) {
7617  $tfld[] = array(
7618  "fld" => $this->getDocAnchor($fldid, '_blank', true, '', false, 'latest', true)
7619  );
7620  }
7621  }
7622  $this->lay->setBlockData("FOLDERS", $tfld);
7623  }
7624  if ($this->allocated == 0) {
7625  $this->lay->eSet("allocate", _("no allocate"));
7626  $this->lay->rSet("allocateid", false);
7627  } else {
7628  $user = new Account("", ($this->allocated));
7629  $this->lay->eSet("allocate", $user->firstname . " " . $user->lastname);
7630  $this->lay->rSet("allocateid", $user->fid);
7631  }
7632 
7633  $tms = $this->getAttachedTimers();
7634 
7635  $this->lay->rSet("Timers", (count($tms) > 0));
7636  }
7637  /**
7638  * @templateController controller for abstract view
7639  * write layout for abstract view
7640  * @param string $target
7641  * @param bool $ulink
7642  * @param bool $abstract
7643  */
7644  function viewabstractcard($target = "finfo", $ulink = true,
7645  /* @noinspection PhpUnusedParameterInspection */
7646  $abstract = false)
7647  {
7648  $listattr = $this->GetAbstractAttributes();
7649 
7650  $tableframe = array();
7651 
7652  foreach ($listattr as $i => $attr) {
7653  //------------------------------
7654  // Compute value elements
7655  $value = $this->getRawValue($i);
7656 
7657  if (($attr->mvisibility != "H") && ($attr->mvisibility != "I")) {
7658  $dValue = '';
7659  switch ($attr->type) {
7660  case "image":
7661  $iValue = $this->GetHtmlValue($listattr[$i], $value, $target, $ulink, -1, true, true);
7662  if ($iValue != "") {
7663  if ($value) {
7664  $dValue = "<img align=\"absbottom\" height=\"30px\" src=\"" . $iValue . "&height=30\">";
7665  } else {
7666  $dValue = "<img align=\"absbottom\" height=\"30px\" src=\"" . $iValue . "\">";
7667  }
7668  }
7669  break;
7670 
7671  default:
7672  $dValue = $this->getHtmlValue($listattr[$i], $value, $target, $ulink = 1, -1, true, true);
7673 
7674  break;
7675  }
7676  if ($dValue !== '') {
7677  $tableframe[] = array(
7678  "name" => $attr->getLabel() ,
7679  "aid" => $attr->id,
7680  "value" => $dValue
7681  );
7682  }
7683  }
7684  }
7685  $this->lay->SetBlockData("TABLEVALUE", $tableframe);
7686  }
7687  /**
7688  * set V_<attrid> and L_<attrid> keys for current layout
7689  * the keys are in uppercase letters
7690  * @param string $target HTML target for links
7691  * @param bool $ulink set to true to have HTML hyperlink when it is possible
7692  * @param bool $abstract set to true to restrict to abstract attributes
7693  * @param bool $viewhidden set to true to return also hidden attribute (visibility H)
7694  */
7695  final public function viewattr($target = "_self", $ulink = true, $abstract = false, $viewhidden = false)
7696  {
7697  $listattr = $this->GetNormalAttributes();
7698  // each value can be instanced with L_<ATTRID> for label text and V_<ATTRID> for value
7699  foreach ($listattr as $k => $v) {
7700  $value = chop($this->getRawValue($v->id));
7701  //------------------------------
7702  // Set the table value elements
7703  $this->lay->Set("S_" . strtoupper($v->id) , ($value != ""));
7704  // don't see non abstract if not
7705  if ((($v->mvisibility == "H") && (!$viewhidden)) || ($v->mvisibility == "I") || (($abstract) && (!$v->isInAbstract))) {
7706  $this->lay->Set("V_" . strtoupper($v->id) , "");
7707  $this->lay->Set("L_" . strtoupper($v->id) , "");
7708  } else {
7709  if ($target == "ooo") {
7710  if ($v->type == "array") {
7711  $tva = $this->getArrayRawValues($v->id);
7712 
7713  $tmkeys = array();
7714  foreach ($tva as $kindex => $kvalues) {
7715  foreach ($kvalues as $kaid => $va) {
7716  /*
7717  * @var NormalAttribute $oa
7718  */
7719  $oa = $this->getAttribute($kaid);
7720  if ($oa->getOption("multiple") == "yes") {
7721  // second level
7722  $oa->setOption("multiple", "no"); // needto have values like first level
7723  $values = explode("<BR>", $va);
7724  $ovalues = array();
7725  foreach ($values as $ka => $vaa) {
7726  $ovalues[] = htmlspecialchars_decode($this->GetOOoValue($oa, $vaa) , ENT_QUOTES);
7727  }
7728  //print_r(array($oa->id=>$ovalues));
7729  $tmkeys[$kindex]["V_" . strtoupper($kaid) ] = $ovalues;
7730  $oa->setOption("multiple", "yes"); // needto have values like first level
7731 
7732  } else {
7733  $oooValue = $this->GetOOoValue($oa, $va);
7734  if ($oa->type !== "htmltext") {
7735  $oooValue = htmlspecialchars_decode($oooValue, ENT_QUOTES);
7736  }
7737  $tmkeys[$kindex]["V_" . strtoupper($kaid) ] = $oooValue;
7738  }
7739  }
7740  }
7741  //print_r($tmkeys);
7742  $this->lay->setRepeatable($tmkeys);
7743  } else {
7744  $ovalue = $this->GetOOoValue($v, $value);
7745  if ($v->isMultiple()) $ovalue = str_replace("<text:tab/>", ', ', $ovalue);
7746  $this->lay->Set("V_" . strtoupper($v->id) , $ovalue);
7747  // print_r(array("V_".strtoupper($v->id)=>$this->GetOOoValue($v, $value),"raw"=>$value));
7748  if ((!$v->inArray()) && ($v->getOption("multiple") == "yes")) {
7749  $values = $this->getMultipleRawValues($v->id);
7750  $ovalues = array();
7751  $v->setOption("multiple", "no");
7752  foreach ($values as $ka => $va) {
7753  $ovalues[] = htmlspecialchars_decode($this->GetOOoValue($v, $va) , ENT_QUOTES);
7754  }
7755  $v->setOption("multiple", "yes");
7756  //print_r(array("V_".strtoupper($v->id)=>$ovalues,"raw"=>$values));
7757  $this->lay->setColumn("V_" . strtoupper($v->id) , $ovalues);
7758  } else {
7759  //$this->lay->Set("V_" . strtoupper($v->id), $this->GetOOoValue($v, $value));
7760 
7761  }
7762  }
7763  } else $this->lay->Set("V_" . strtoupper($v->id) , $this->GetHtmlValue($v, $value, $target, $ulink));
7764  $this->lay->Set("L_" . strtoupper($v->id) , $v->getLabel());
7765  }
7766  }
7767  $listattr = $this->GetFieldAttributes();
7768  // each value can be instanced with L_<ATTRID> for label text and V_<ATTRID> for value
7769  foreach ($listattr as $k => $v) {
7770  $this->lay->Set("L_" . strtoupper($v->id) , $v->getLabel());
7771  }
7772  }
7773  /**
7774  * set properties keys in current layout
7775  * the keys are in uppercase letters
7776  * produce alse V_TITLE key to have a HTML link to document (for HTML layout)
7777  * @param string $target
7778  * @param bool $ulink for the V_TITLE key
7779  * @param bool $abstract unused
7780  */
7781  final public function viewprop($target = "_self", $ulink = true,
7782  /* @noinspection PhpUnusedParameterInspection */
7783  $abstract = false)
7784  {
7785  foreach ($this->fields as $k => $v) {
7786  if ($target == 'ooo') $this->lay->Set(strtoupper($v) , ($this->$v === null) ? false : str_replace(array(
7787  "<",
7788  ">",
7789  '&'
7790  ) , array(
7791  "&lt;",
7792  "&gt;",
7793  "&amp;"
7794  ) , $this->$v));
7795  else $this->lay->Set(strtoupper($v) , ($this->$v === null) ? false : $this->$v);
7796  }
7797  if ($target == 'ooo') $this->lay->Set("V_TITLE", $this->lay->get("TITLE"));
7798  else $this->lay->Set("V_TITLE", $this->getDocAnchor($this->id, $target, $ulink, false, false));
7799  }
7800  /**
7801  * affect a logical name that can be use as unique reference of a document independant of database
7802  * @param string $name new logical name
7803  * @param bool $reset set to true to accept change
7804  * @deprecated use ::setLogicalName instead
7805  * @return string error message if cannot be
7806  */
7808  {
7810  return $this->setLogicalName($name, $reset);
7811  }
7812  /**
7813  * Affect a logical name that can be use as unique reference of a document independant of database.
7814  *
7815  * The logical name is affected only if it's not an empty string or NULL:
7816  * if empty or NULL, then the affectation is silently bypassed.
7817  *
7818  * @param string $name new logical name
7819  * @param bool $reset set to true to accept change
7820  * @param bool $verifyOnly if true only verify syntax and unicity
7821  * @return string error message if cannot be
7822  */
7823  function setLogicalName($name, $reset = false, $verifyOnly = false)
7824  {
7825  if ($name === "" || $name === null) {
7826  return '';
7827  }
7829  if (!$this->isAffected()) {
7830  $this->name = $name; // affect to be controlled in add and return error also
7831 
7832  }
7833  return (sprintf(_("name must begin with a letter and contain only alphanumeric characters or - and _: invalid [%s]") , $name));
7834  } elseif (!$verifyOnly && !$this->isAffected()) {
7835  $this->name = $name;
7836 
7837  return "";
7838  } elseif (!$verifyOnly && $this->isAffected() && ($this->name != "") && ($this->doctype != 'Z') && !$reset) {
7839  return (sprintf(_("Logical name %s already set for %s. Use reset parameter to overhide it") , $name, $this->title));
7840  } else {
7841  // verify not use yet
7842  $d = getTDoc($this->dbaccess, $name);
7843  if ($d && $d["doctype"] != 'Z') {
7844  return sprintf(_("Logical name %s already use in document %s") , $name, $d["title"]);
7845  } elseif (!$verifyOnly) {
7846 
7847  if ($this->name) {
7848  simpleQuery($this->dbaccess, sprintf("UPDATE docname SET name = '%s' WHERE name = '%s'", pg_escape_string($name) , pg_escape_string($this->name)));
7849  }
7850  $this->name = $name;
7851 
7852  simpleQuery("", sprintf("update %s set name='%s' where initid=%d", pg_escape_string($this->dbtable) , pg_escape_string($name) , $this->initid));
7853  simpleQuery("", sprintf("select name from docname where id=%d", $this->id) , $dbdocname, true, true);
7854 
7855  if (!$dbdocname) {
7856  $sql = sprintf("delete from docname where name='%s';insert into docname (id,fromid,name) select id, fromid, name from docread where name='%s' and locked != -1", pg_escape_string($name) , pg_escape_string($name));
7857  simpleQuery("", $sql);
7858  }
7859  }
7860  }
7861  return "";
7862  }
7863  /**
7864  * view only option values
7865  * @templateController
7866  * @deprecated option attributes are not supported
7867  * @param string $target
7868  * @param bool $ulink
7869  * @param bool $abstract
7870  * @return void
7871  */
7872  final public function viewoptcard($target = "_self", $ulink = true, $abstract = false)
7873  {
7875  $this->viewbodycard($target, $ulink, $abstract, true);
7876  }
7877  /**
7878  * edit only option
7879  * @templateController
7880  * @deprecated option attributes are not supported
7881  * @param string $target
7882  * @param bool $ulink
7883  * @param bool $abstract
7884  * @return void
7885  */
7886  final public function editoptcard($target = "_self", $ulink = true, $abstract = false)
7887  {
7889  $this->editbodycard($target, $ulink, $abstract, true);
7890  }
7891  /**
7892  * value for edit interface
7893  * @templateController default control for HTML form document edition
7894  * @param string $target
7895  * @param bool $ulink
7896  * @param bool $abstract
7897  * @param bool $onlyopt if true only optional attributes are displayed
7898  * @throws \Dcp\Core\Exception
7899  */
7900  function editbodycard(
7901  /* @noinspection PhpUnusedParameterInspection */
7902  $target = "_self", $ulink = true, $abstract = false, $onlyopt = false)
7903  {
7904  include_once ("FDL/editutil.php");
7905  include_once ("FDL/Class.SearchDoc.php");
7906 
7907  $docid = $this->id; // document to edit
7908  // ------------------------------------------------------
7909  // new or modify ?
7910  if ($docid == 0) {
7911  // new document
7912  if ($this->fromid > 0) {
7913  $cdoc = $this->getFamilyDocument();
7914  $this->lay->Set("title", sprintf(_("new %s") , $cdoc->getHtmlTitle()));
7915  }
7916  } else {
7917  // when modification
7918 
7919  /*
7920  * @var Action $action
7921  */
7922  global $action;
7923  if (!$this->isAlive()) $action->ExitError(_("document not referenced"));
7924  $this->lay->Set("title", $this->getHtmlTitle());
7925  }
7926  $this->lay->Set("id", $docid);
7927  $this->lay->Set("classid", $this->fromid);
7928  // get inline help
7929  $help = $this->getHelpPage();
7930  // ------------------------------------------------------
7931  // Perform SQL search for doc attributes
7932  // ------------------------------------------------------
7933  $frames = array();
7934  $listattr = $this->GetInputAttributes($onlyopt);
7935 
7936  $k = 0; // number of frametext
7937  $v = 0; // number of value in one frametext
7938  $currentFrameId = "";
7939  /*
7940  * @var NormalAttribute $currentFrame
7941  */
7942  $currentFrame = null;
7943  $changeframe = false;
7944  $ih = 0; // index for hidden values
7945  $thidden = array();
7946  $tableframe = array();
7947  $ttabs = array();
7948  $frametpl = '';
7949  $iattr = 0;
7950  foreach ($listattr as $i => $attr) {
7951  $iattr++;
7952  // Compute value elements
7953  if ($docid > 0) $value = $this->getRawValue($attr->id);
7954  else {
7955  $value = $this->getRawValue($attr->id);
7956  // $value = $this->GetValueMethod($this->GetValue($listattr[$i]->id));
7957 
7958  }
7959  if (!$attr->fieldSet) {
7960  addWarningMsg(sprintf(_("unknow set for attribute %s %s") , $attr->id, $attr->getLabel()));
7961  continue;
7962  }
7963 
7964  if ($currentFrameId != $attr->fieldSet->id) {
7965  if ($currentFrameId != "") $changeframe = true;
7966  }
7967  if ($changeframe) { // to generate final frametext
7968  $changeframe = false;
7969  /*
7970  * @var BasicAttribute $oaf
7971  */
7972  $oaf = $this->getAttribute($currentFrameId);
7973  if ($v > 0 || $frametpl) { // one value detected
7974  if ($oaf->getOption("vlabel") == "none") $currentFrameText = '';
7975  else $currentFrameText = mb_ucfirst($oaf->GetLabel());
7976 
7977  $frames[$k]["frametext"] = $currentFrameText;
7978  $frames[$k]["frameid"] = $oaf->id;
7979  $frames[$k]["tag"] = "";
7980  $frames[$k]["TAB"] = false;
7981  $frames[$k]["edittpl"] = ($frametpl != "");
7982  $frames[$k]["zonetpl"] = ($frametpl != "") ? sprintf("[ZONE FDL:EDITTPL?id=%d&famid=%d&zone=%s]", $this->id, $this->fromid, $frametpl) : '';
7983  $oaf = $this->getAttribute($oaf->id);
7984  $frames[$k]["bgcolor"] = $oaf ? $oaf->getOption("bgcolor", false) : false;
7985  $frames[$k]["ehelp"] = ($help->isAlive()) ? $help->getAttributeHelpUrl($oaf->id) : false;
7986  $frames[$k]["ehelpid"] = ($help->isAlive()) ? $help->id : false;
7987  if ($oaf && $oaf->fieldSet && ($oaf->fieldSet->id != "") && ($oaf->fieldSet->id != Adoc::HIDDENFIELD)) {
7988  $frames[$k]["tag"] = "TAG" . $oaf->fieldSet->id;
7989  $frames[$k]["TAB"] = true;
7990  $ttabs[$oaf->fieldSet->id] = array(
7991  "tabid" => $oaf->fieldSet->id,
7992  "tabtitle" => ($oaf->fieldSet->getOption("vlabel") == "none") ? '&nbsp;' : mb_ucfirst($oaf->fieldSet->getLabel())
7993  );
7994  }
7995  $frames[$k]["TABLEVALUE"] = "TABLEVALUE_$k";
7996  $this->lay->SetBlockData($frames[$k]["TABLEVALUE"], $tableframe);
7997  unset($tableframe);
7998  $tableframe = array();
7999  $k++;
8000  }
8001  $v = 0;
8002  }
8003 
8004  $currentFrameId = $listattr[$i]->fieldSet->id;
8005  $currentFrame = $attr->fieldSet;
8006 
8007  if ($currentFrame->mvisibility == 'R' || $currentFrame->mvisibility == 'H' || $currentFrame->mvisibility == 'I') {
8008  $frametpl = '';
8009  } else {
8010  $frametpl = $currentFrame->getOption("edittemplate");
8011  }
8012  if (!$frametpl) {
8013  //------------------------------
8014  // Set the table value elements
8015  if (($listattr[$i]->mvisibility == "H") || ($listattr[$i]->mvisibility == "R")) {
8016  // special case for hidden values
8017  if ($listattr[$i]->type != "array") {
8018  $thidden[$ih]["hname"] = "_" . $listattr[$i]->id;
8019  $thidden[$ih]["hid"] = $listattr[$i]->id;
8020  if (($value == "") && ($this->id == 0)) $thidden[$ih]["hvalue"] = GetHttpVars($listattr[$i]->id);
8021  else $thidden[$ih]["hvalue"] = chop(htmlentities($value, ENT_COMPAT, "UTF-8"));
8022 
8023  $thidden[$ih]["inputtype"] = getHtmlInput($this, $listattr[$i], $value, "", "", true);
8024  }
8025  $ih++;
8026  } else {
8027  $tableframe[$v]["value"] = chop(htmlentities($value, ENT_COMPAT, "UTF-8"));
8028  $label = $listattr[$i]->getLabel();
8029  $tableframe[$v]["attrid"] = $listattr[$i]->id;
8030  $tableframe[$v]["name"] = mb_ucfirst($label);
8031 
8032  if ($listattr[$i]->needed) $tableframe[$v]["labelclass"] = "FREEDOMLabelNeeded";
8033  else $tableframe[$v]["labelclass"] = "FREEDOMLabel";
8034  $tableframe[$v]["aneeded"] = $listattr[$i]->needed;
8035  $elabel = $listattr[$i]->getoption("elabel");
8036  $elabel = str_replace("'", "&rsquo;", $elabel);
8037  $tableframe[$v]["elabel"] = mb_ucfirst(str_replace('"', "&rquot;", $elabel));
8038  $tableframe[$v]["aehelp"] = ($help->isAlive()) ? $help->getAttributeHelpUrl($listattr[$i]->id) : false;
8039  $tableframe[$v]["aehelpid"] = ($help->isAlive()) ? $help->id : false;
8040 
8041  $tableframe[$v]["multiple"] = ($attr->getOption("multiple") == "yes") ? "true" : "false";
8042  $tableframe[$v]["atype"] = $attr->type;
8043  $tableframe[$v]["name"] = mb_ucfirst($label);
8044  $tableframe[$v]["classback"] = ($attr->usefor == "O") ? "FREEDOMOpt" : "FREEDOMBack1";
8045 
8046  $tableframe[$v]["SINGLEROW"] = true;
8047 
8048  $vlabel = $listattr[$i]->getOption("vlabel");
8049  if ((($listattr[$i]->type == "array") && ($vlabel != 'left')) || (($listattr[$i]->type == "htmltext") && ($vlabel != 'left')) || ($vlabel == 'up') || ($vlabel == 'none')) $tableframe[$v]["SINGLEROW"] = false;
8050 
8051  $tableframe[$v]["viewlabel"] = (($listattr[$i]->type != "array") && ($vlabel != 'none'));
8052  $edittpl = $listattr[$i]->getOption("edittemplate");
8053  if ($edittpl) {
8054  if ($edittpl == "none") {
8055  unset($tableframe[$v]);
8056  } else {
8057  if ($this->getZoneOption($edittpl) == 'S') {
8058  $tableframe[$v]["SINGLEROW"] = false;
8059  $tableframe[$v]["viewlabel"] = false;
8060  }
8061  $tableframe[$v]["inputtype"] = sprintf("[ZONE FDL:EDITTPL?id=%d&famid=%d&zone=%s]", $this->id, $this->fromid, $edittpl);
8062  }
8063  } else {
8064  $tableframe[$v]["inputtype"] = getHtmlInput($this, $listattr[$i], $value);
8065  }
8066  $v++;
8067  }
8068  }
8069  }
8070  // Out
8071  if ($currentFrameId != '') {
8072  $oaf = $this->getAttribute($currentFrameId);
8073  if ($oaf->mvisibility == 'R' || $oaf->mvisibility == 'H' || $oaf->mvisibility == 'I') {
8074  $frametpl = '';
8075  } else {
8076  $frametpl = $oaf->getOption("edittemplate");
8077  }
8078  if ($v > 0 || $frametpl) { // latest fieldset
8079  if ($oaf->getOption("vlabel") == "none") $currentFrameText = '';
8080  else $currentFrameText = mb_ucfirst($oaf->GetLabel());
8081  $frames[$k]["frametext"] = $currentFrameText;
8082  $frames[$k]["frameid"] = $oaf->id;
8083  $frames[$k]["TABLEVALUE"] = "TABLEVALUE_$k";
8084  $frames[$k]["tag"] = "";
8085  $frames[$k]["TAB"] = false;
8086  $frames[$k]["edittpl"] = ($frametpl != "");
8087  $frames[$k]["zonetpl"] = ($frametpl != "") ? sprintf("[ZONE FDL:EDITTPL?id=%d&famid=%d&zone=%s]", $this->id, $this->fromid, $frametpl) : '';
8088  $frames[$k]["ehelp"] = ($help->isAlive()) ? $help->getAttributeHelpUrl($oaf->id) : false;
8089  $frames[$k]["ehelpid"] = ($help->isAlive()) ? $help->id : false;
8090 
8091  $oaf = $this->getAttribute($oaf->id);
8092  $frames[$k]["bgcolor"] = $oaf ? $oaf->getOption("bgcolor", false) : false;
8093  if (($currentFrame->fieldSet->id != "") && ($currentFrame->fieldSet->id != Adoc::HIDDENFIELD)) {
8094  $frames[$k]["tag"] = "TAG" . $currentFrame->fieldSet->id;
8095  $frames[$k]["TAB"] = true;
8096  $ttabs[$currentFrame->fieldSet->id] = array(
8097  "tabid" => $currentFrame->fieldSet->id,
8098  "tabtitle" => ($currentFrame->fieldSet->getOption("vlabel") == "none") ? '&nbsp;' : mb_ucfirst($currentFrame->fieldSet->getLabel())
8099  );
8100  }
8101  $this->lay->SetBlockData($frames[$k]["TABLEVALUE"], $tableframe);
8102  }
8103  }
8104  $this->lay->SetBlockData("HIDDENS", $thidden);
8105  $this->lay->SetBlockData("TABLEBODY", $frames);
8106  $this->lay->SetBlockData("TABS", $ttabs);
8107  $this->lay->Set("ONETAB", count($ttabs) > 0);
8108  $this->lay->Set("fromid", $this->fromid);
8109  $this->lay->Set("docid", $this->id);
8110  if (count($ttabs) > 0) {
8111  $this->lay->Set("firsttab", false);
8112  $ut = $this->getUtag("lasttab");
8113  if ($ut) $firstopen = $ut->comment; // last memo tab
8114  else $firstopen = false;
8115 
8116  foreach ($ttabs as $k => $v) {
8117  $oa = $this->getAttribute($k);
8118  if ($oa->getOption("firstopen") == "yes") $this->lay->Set("firsttab", $k);
8119  if ($firstopen == $oa->id) $this->lay->Set("firsttab", $k);
8120  }
8121  }
8122  }
8123  /**
8124  * add V_<<ATTRID> keys for HTML form in current layout
8125  * add also L_<ATTRID> for attribute labels
8126  * create input fields for attribute document
8127  * @param bool $withtd set to false if don't wan't <TD> tag in the middle bet<een fields and button
8128  */
8129  final public function editattr($withtd = true)
8130  {
8131 
8132  include_once ("FDL/editutil.php");
8133  $listattr = $this->GetNormalAttributes();
8134  // each value can be instanced with L_<ATTRID> for label text and V_<ATTRID> for value
8135  foreach ($listattr as $k => $v) {
8136  //------------------------------
8137  // Set the table value elements
8138  $value = chop($this->getRawValue($v->id));
8139  if ($v->mvisibility == "R") $v->mvisibility = "H"; // don't see in edit mode
8140  $this->lay->Set("V_" . strtoupper($v->id) , getHtmlInput($this, $v, $value, "", "", (!$withtd)));
8141  if ($v->needed == "Y") $this->lay->Set("L_" . strtoupper($v->id) , "<B>" . $v->getLabel() . "</B>");
8142  else $this->lay->Set("L_" . strtoupper($v->id) , $v->getLabel());
8143  $this->lay->Set("W_" . strtoupper($v->id) , ($v->mvisibility != "H"));
8144  }
8145 
8146  $listattr = $this->GetFieldAttributes();
8147  // each value can be instanced with L_<ATTRID> for label text and V_<ATTRID> for value
8148  foreach ($listattr as $k => $v) {
8149  $this->lay->Set("L_" . strtoupper($v->id) , $v->getLabel());
8150  }
8151 
8152  $this->setFamidInLayout();
8153  }
8154  /**
8155  * add IDFAM_<famNAme> keys in current layout
8156  */
8157  final public function setFamidInLayout()
8158  {
8159  // add IDFAM_ attribute in layout
8160  global $tFamIdName;
8161 
8162  if (!isset($tFamIdName)) getFamIdFromName($this->dbaccess, "-");
8163 
8164  reset($tFamIdName);
8165  foreach ($tFamIdName as $k => $v) {
8166  $this->lay->set("IDFAM_$k", $v);
8167  }
8168  }
8169  /**
8170  * get vault file name or server path of filename
8171  * @param string $attrid identifier of file attribute
8172  * @param bool $path false return original file name (basename) , true the real path
8173  * @param int $index in case of array of files
8174  * @return string the file name of the attribute
8175  */
8176  final public function vault_filename($attrid, $path = false, $index = - 1)
8177  {
8178  if ($index == - 1) $fileid = $this->getRawValue($attrid);
8179  else $fileid = $this->getMultipleRawValues($attrid, '', $index);
8180  return $this->vault_filename_fromvalue($fileid, $path);
8181  }
8182  /**
8183  * get vault file name or server path of filename
8184  * @param string $fileid value of file attribute
8185  * @param bool $path false return original file name (basename) , true the real path
8186  * @return string the file name of the attribute
8187  */
8188  final public function vault_filename_fromvalue($fileid, $path = false)
8189  {
8190  $fname = "";
8191  if (preg_match(PREGEXPFILE, $fileid, $reg)) {
8192  // reg[1] is mime type
8193  $vf = newFreeVaultFile($this->dbaccess);
8194  /*
8195  * @var vaultFileInfo $info
8196  */
8197  if ($vf->Show($reg[2], $info) == "") {
8198  if ($path) $fname = $info->path;
8199  else $fname = $info->name;
8200  }
8201  }
8202  return $fname;
8203  }
8204  /**
8205  * get vault file name or server path of filename
8206  * @param NormalAttribute $attr identifier of file attribute
8207  * @return array of properties :
8208  [0]=>
8209  [name] => TP_Users.pdf
8210  [size] => 179435
8211  [public_access] =>
8212  [mime_t] => PDF document, version 1.4
8213  [mime_s] => application/pdf
8214  [cdate] => 24/12/2010 11:44:36
8215  [mdate] => 24/12/2010 11:44:41
8216  [adate] => 25/03/2011 08:13:34
8217  [teng_state] => 1
8218  [teng_lname] => pdf
8219  [teng_vid] => 15
8220  [teng_comment] =>
8221  [path] => /var/www/eric/vaultfs/1/16.pdf
8222  [vid] => 16
8223  */
8224  final public function vault_properties(NormalAttribute $attr)
8225  {
8226  if ($attr->inArray()) $fileids = $this->getMultipleRawValues($attr->id);
8227  else $fileids[] = $this->getRawValue($attr->id);
8228 
8229  $tinfo = array();
8230  foreach ($fileids as $k => $fileid) {
8231  if (preg_match(PREGEXPFILE, $fileid, $reg)) {
8232  // reg[1] is mime type
8233  $vf = newFreeVaultFile($this->dbaccess);
8234  /*
8235  * @var vaultFileInfo $info
8236  */
8237  if ($vf->Show($reg[2], $info) == "") {
8238  $tinfo[$k] = get_object_vars($info);
8239  $tinfo[$k]["vid"] = $reg[2];
8240  }
8241  }
8242  }
8243 
8244  return $tinfo;
8245  }
8246  /**
8247  * return a property of vault file value
8248  * @param string $filesvalue the file value : like application/pdf|12345
8249  * @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
8250  * @param string $returnType if "array" return indexed array else return VaultFileInfo object
8251  * @return array|string|VaultFileInfo value of property or array of all properties if no key
8252  */
8253  final public function getFileInfo($filesvalue, $key = "", $returnType = "array")
8254  {
8255  if (!is_string($filesvalue)) return false;
8256  if (preg_match(PREGEXPFILE, $filesvalue, $reg)) {
8257  include_once ("FDL/Lib.Vault.php");
8258  $vid = $reg[2];
8259  $info = vault_properties($vid);
8260  if (!$info) return false;
8261  if ($key != "") {
8262  if (isset($info->$key)) return $info->$key;
8263  else return sprintf(_("unknow %s file property") , $key);
8264  } else {
8265  if ($returnType === "array") {
8266  return get_object_vars($info);
8267  } else {
8268  return $info;
8269  }
8270  }
8271  }
8272  return $key ? '' : array();
8273  }
8274  /**
8275  *
8276  * @param string &$xml content xml (empty if $outfile is not empty
8277  * @param boolean $withfile include files in base64 encoded
8278  * @param string $outfile if not empty means content is put into this file
8279  * @param bool $wident set true to ident xml
8280  * @param bool $flat set to true if don't want structure
8281  * @param array $exportAttributes to export only a part of attributes
8282  * @return string error message (empty if no error)
8283  */
8284  public function exportXml(&$xml, $withfile = false, $outfile = "", $wident = true, $flat = false, $exportAttributes = array())
8285  {
8286  try {
8287  $exd = new Dcp\ExportXmlDocument();
8288  $exd->setDocument($this);
8289  $exd->setExportFiles($withfile);
8290  $exd->setExportDocumentNumericIdentiers($wident);
8291  $exd->setStructureAttributes(!$flat);
8292  $exd->setIncludeSchemaReference(!$flat);
8293  $exd->setAttributeToExport($exportAttributes);
8294 
8295  if ($outfile) {
8296  $exd->writeTo($outfile);
8297  } else {
8298  $xml = $exd->getXml();
8299  }
8300  }
8301  catch(Dcp\Exception $e) {
8302  errorLogException($e);
8303  return $e->getMessage();
8304  }
8305  return '';
8306  }
8307  // =====================================================================================
8308  // ================= Methods use for XML ======================
8309 
8310  /**
8311  * @deprecated use exportXml instead
8312  * @param bool $withdtd
8313  * @param string $id_doc
8314  * @return string
8315  */
8316  final public function toxml($withdtd = false, $id_doc = "")
8317  {
8319  /*
8320  * @var Action $action
8321  */
8322  global $action;
8323 
8324  $docid = intval($this->id);
8325  if ($id_doc == "") {
8326  $id_doc = $docid;
8327  }
8328 
8329  $title = $this->title;
8330  $fam_doc = new_Doc($this->dbaccess, $this->fromid);
8331  $name = str_replace(" ", "_", $fam_doc->title);
8332 
8333  if ($withdtd == true) {
8334  $dtd = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>";
8335  $dtd.= "<!DOCTYPE $name [";
8336  /* @noinspection PhpDeprecationInspection */
8337  $dtd.= $this->todtd();
8338  $dtd.= "]>";
8339  } else {
8340  $dtd = "";
8341  }
8342 
8343  $this->lay = new Layout("FDL/Layout/viewxml.xml", $action);
8344  $this->lay->Set("DTD", $dtd);
8345  $this->lay->Set("NOM_FAM", $name);
8346  $this->lay->Set("id_doc", $id_doc);
8347  $this->lay->Set("TITRE", $title);
8348  $this->lay->Set("ID_FAM", $fam_doc->name);
8349  $this->lay->Set("revision", $this->revision);
8350  $this->lay->Set("revdate", $this->revdate);
8351  //$this->lay->Set("IDOBJECT",$docid);
8352  //$this->lay->Set("IDFAM",$fromid);
8353  //$idfam=$fam_doc->classname;
8354  //$this->lay->Set("TYPEOBJECT",$doctype);
8355  ////debut
8356  $listattr = $this->GetNormalAttributes();
8357 
8358  $frames = array();
8359 
8360  $nattr = count($listattr); // attributes list count
8361  $k = 0; // number of frametext
8362  $v = 0; // number of value in one frametext
8363  $currentFrameId = "";
8364 
8365  $changeframe = false; // is true when need change frame
8366  $tableframe = array();
8367 
8368  $iattr = 0;
8369 
8370  foreach ($listattr as $i => $attr) {
8371  $iattr++;
8372 
8373  if ((chop($listattr[$i]->id) != "") && ($listattr[$i]->id != Adoc::HIDDENFIELD)) {
8374  //------------------------------
8375  // Compute value elements
8376  if ($currentFrameId != $listattr[$i]->fieldSet->id) {
8377  if ($currentFrameId != "") $changeframe = true;
8378  }
8379  //------------------------------
8380  // change frame if needed
8381  if ( // to generate fiedlset
8382  $changeframe) {
8383  $changeframe = false;
8384  if ($v > 0) // one value detected
8385  {
8386 
8387  $frames[$k]["FIELD"] = $currentFrameId;
8388  $frames[$k]["ARGUMENT"] = "ARGUMENT_$k";
8389 
8390  $this->lay->SetBlockData($frames[$k]["ARGUMENT"], $tableframe);
8391  $frames[$k]["nom_fieldset"] = $this->GetLabel($currentFrameId);
8392  unset($tableframe);
8393  $tableframe = array();
8394  $k++;
8395  }
8396  $v = 0;
8397  }
8398  // Set the table value elements
8399  if (($iattr <= $nattr) && ($this->getRawValue($i) != "")) {
8400  $attrtype_list = false;
8401 
8402  if (strstr($listattr[$i]->type, "textlist") != false) {
8403  $attrtype_list = true;
8404  }
8405  if ($listattr[$i]->inArray()) {
8406  $attrtype_list = true;
8407  }
8408 
8409  if ($attrtype_list) {
8410  // $value=htmlspecialchars($this->GetValue($i));
8411  $value = $this->getRawValue($i);
8412  $textlist = $this->rawValueToArray($value);
8413 
8414  while ($text = each($textlist)) {
8415  $currentFrameId = $listattr[$i]->fieldSet->id;
8416  $tableframe[$v]["id"] = $listattr[$i]->id;
8417  $tableframe[$v]["value"] = $text[1];
8418  $tableframe[$v]["type"] = base64_encode($listattr[$i]->type);
8419  $tableframe[$v]["labelText"] = (str_replace(array(
8420  "%",
8421  "\""
8422  ) , array(
8423  "",
8424  "\\\""
8425  ) , $listattr[$i]->getLabel()));
8426  //$tableframe[$v]["type"]=$listattr[$i]->type;
8427  //$tableframe[$v]["visibility"]=$listattr[$i]->visibility;
8428  //$tableframe[$v]["needed"]=$listattr[$i]->needed;
8429  $v++;
8430  }
8431  } else {
8432  $value = htmlspecialchars($this->getRawValue($i));
8433  $tableframe[$v]["type"] = base64_encode($listattr[$i]->type);
8434 
8435  $currentFrameId = $listattr[$i]->fieldSet->id;
8436  $tableframe[$v]["id"] = $listattr[$i]->id;
8437  $tableframe[$v]["value"] = $value;
8438  $tableframe[$v]["labelText"] = addslashes($listattr[$i]->getLabel());
8439  //$tableframe[$v]["type"]=$listattr[$i]->type;
8440  //$tableframe[$v]["visibility"]=$listattr[$i]->visibility;
8441  //$tableframe[$v]["needed"]=$listattr[$i]->needed;
8442  $v++;
8443  }
8444  }
8445  }
8446  }
8447 
8448  if ($v > 0) // last fieldset
8449  {
8450 
8451  $frames[$k]["FIELD"] = $currentFrameId;
8452  $frames[$k]["ARGUMENT"] = "ARGUMENT_$k";
8453 
8454  $this->lay->SetBlockData($frames[$k]["ARGUMENT"], $tableframe);
8455  $frames[$k]["nom_fieldset"] = $this->GetLabel($currentFrameId);
8456  unset($tableframe);
8457  }
8458 
8459  $this->lay->SetBlockData("FIELDSET", $frames);
8460  return $this->lay->gen();
8461  }
8462  /**
8463  * @deprecated use exportXml instead
8464  * @return string
8465  */
8466  final public function todtd()
8467  {
8469  global $action;
8470  $this->lay = new Layout("FDL/Layout/viewdtd.xml", $action);
8471 
8472  $fam_doc = $this->getFamilyDocument();
8473  $name = str_replace(" ", "_", $fam_doc->title);
8474  $this->lay->Set("doctype", $this->doctype);
8475  $this->lay->Set("idfam", $this->fromid);
8476  $this->lay->Set("nom_fam", $name);
8477  $this->lay->Set("id_fam", $name);
8478 
8479  $listattr = $this->GetNormalAttributes();
8480 
8481  $frames = $elements = array();
8482 
8483  $nattr = count($listattr); // attributes list count
8484  $k = 0; // number of frametext
8485  $v = 0; // number of value in one frametext
8486  $currentFrameId = "";
8487 
8488  $changeframe = false; // is true when need change frame
8489  $needed = false;
8490  $tableattrs = array();
8491  $tablesetting = array();
8492  $iattr = 0;
8493 
8494  foreach ($listattr as $i => $attr) {
8495  $iattr++;
8496  //------------------------------
8497  // Compute value elements
8498  if ($currentFrameId != $listattr[$i]->fieldSet->id) {
8499  if ($currentFrameId != "") $changeframe = true;
8500  }
8501  //------------------------------
8502  // change frame if needed
8503  if ( // to generate fiedlset
8504  $changeframe) {
8505  $changeframe = false;
8506 
8507  if ($v > 0) // one value detected
8508  {
8509 
8510  $frames[$k]["name"] = $currentFrameId;
8511  $elements[$k]["name"] = $currentFrameId;
8512  if ($needed) {
8513  $elements[$k]["name"].= ", ";
8514  } else {
8515  $elements[$k]["name"].= "?, ";
8516  }
8517  $needed = false;
8518 
8519  $frames[$k]["ATTRIBUT_NAME"] = "ATTRIBUT_NAME_$k";
8520  $frames[$k]["ATTRIBUT_SETTING"] = "ATTRIBUT_SETTING_$k";
8521 
8522  $this->lay->SetBlockData($frames[$k]["ATTRIBUT_NAME"], $tableattrs);
8523 
8524  $this->lay->SetBlockData($frames[$k]["ATTRIBUT_SETTING"], $tablesetting);
8525  unset($tableattrs);
8526  unset($tablesetting);
8527  $tableattrs = array();
8528  $tablesetting = array();
8529 
8530  $k++;
8531  }
8532  $v = 0;
8533  }
8534  // Set the table value elements
8535  if ($iattr <= $nattr) {
8536 
8537  $currentFrameId = $listattr[$i]->fieldSet->id;
8538  $tablesetting[$v]["name_attribut"] = $listattr[$i]->id;
8539  $tablesetting[$v]["labelText"] = addslashes(str_replace("%", "", $listattr[$i]->getLabel()));
8540  $tablesetting[$v]["type"] = base64_encode($listattr[$i]->type);
8541  $tablesetting[$v]["visibility"] = $listattr[$i]->visibility;
8542  if ($listattr[$i]->needed) {
8543  $needed = true;
8544  }
8545 
8546  if ($v == 0) {
8547  $insert = $listattr[$i]->id;
8548  if ($listattr[$i]->type == "textlist") {
8549  if ($listattr[$i]->needed) {
8550  $insert.= "+";
8551  $tableattrs[$v]["name_attribut"] = $insert;
8552  } else {
8553  $insert.= "*";
8554  $tableattrs[$v]["name_attribut"] = $insert;
8555  }
8556  } else {
8557  if ($listattr[$i]->needed) {
8558  $tableattrs[$v]["name_attribut"] = $insert;
8559  } else {
8560  $tableattrs[$v]["name_attribut"] = ($insert . "?");
8561  }
8562  }
8563  } else {
8564  $insert = (", " . $listattr[$i]->id);
8565  if ($listattr[$i]->type == "textlist") {
8566  if ($listattr[$i]->needed) {
8567  $insert.= "+";
8568  } else {
8569  $insert.= "*";
8570  }
8571  $tableattrs[$v]["name_attribut"] = $insert;
8572  } else {
8573  if ($listattr[$i]->needed) {
8574  $tableattrs[$v]["name_attribut"] = $insert;
8575  } else {
8576  $tableattrs[$v]["name_attribut"] = ($insert . "?");
8577  }
8578  }
8579  }
8580  $v++;
8581  }
8582  }
8583 
8584  if ($v > 0) // last fieldset
8585  {
8586  $frames[$k]["name"] = $currentFrameId;
8587  if ($needed) {
8588  $elements[$k]["name"] = $currentFrameId;
8589  } else {
8590  $elements[$k]["name"] = ($currentFrameId . "?");
8591  }
8592  $frames[$k]["ATTRIBUT_NAME"] = "ATTRIBUT_NAME_$k";
8593  $frames[$k]["ATTRIBUT_SETTING"] = "ATTRIBUT_SETTING_$k";
8594  $this->lay->SetBlockData($frames[$k]["ATTRIBUT_NAME"], $tableattrs);
8595 
8596  $this->lay->SetBlockData($frames[$k]["ATTRIBUT_SETTING"], $tablesetting);
8597  unset($tableattrs);
8598  unset($tablesetting);
8599  }
8600 
8601  $this->lay->SetBlockData("FIELDSET", $frames);
8602  $this->lay->SetBlockData("ELEMENT", $elements);
8603  return $this->lay->gen();
8604  }
8605  /**
8606  * define custom title used to set title propert when update or create document
8607  * @api hook called in refresh title
8608  * this method can be redefined in child family to compose specific title
8609  */
8610  public function getCustomTitle()
8611  {
8612  return $this->title;
8613  }
8614  /**
8615  * define custom title used to set title propert when update or create document
8616  * @deprecated This hook may be replaced by getCustomTitle in the the next version.
8617  * this method can be redefined in child family to compose specific title
8618  */
8619  public function getSpecTitle()
8620  {
8621  return $this->title;
8622  }
8623  /**
8624  * @deprecated not needed until 2.0 version
8625  * @param string $nameId
8626  * @param $nameTitle
8627  */
8628  final public function refreshDocTitle($nameId, $nameTitle)
8629  {
8631  // gettitle(D,SI_IDSOC):SI_SOCIETY,SI_IDSOC
8632  $this->AddParamRefresh("$nameId", "$nameTitle");
8633  $doc = new_Doc($this->dbaccess, $this->getRawValue($nameId));
8634  if ($doc->isAlive()) $this->setValue($nameTitle, $doc->title);
8635  else {
8636  // suppress
8637  if (!$doc->isAffected()) $this->clearValue($nameId);
8638  }
8639  }
8640  /**
8641  * get filename image emblem for the doc like lock/nowrite
8642  * @param int $size image width in pixel
8643  * @return string the url of the image
8644  */
8645  function getEmblem($size = null)
8646  {
8647  /*
8648  * @var Action $action
8649  */
8650  global $action;
8651  if ($this->confidential > 0) return $action->parent->getImageLink("confidential.gif", true, $size);
8652  else if ($this->locked == - 1) return $action->parent->getImageLink("revised.png", true, $size);
8653  else if ($this->lockdomainid > 0) {
8654  if ($this->locked > 0) {
8655  if ((abs($this->locked) == $this->userid)) return $action->parent->getImageLink("lockorange.png", true, $size);
8656  else return $action->parent->getImageLink("lockred.png", true, $size);
8657  } else return $action->parent->getImageLink("lockorange.png", true, $size);
8658  } else if ($this->allocated == $this->userid) return $action->parent->getImageLink("lockblue.png", true, $size);
8659  else if ((abs($this->locked) == $this->userid)) return $action->parent->getImageLink("lockgreen.png", true, $size);
8660  else if ($this->locked != 0) return $action->parent->getImageLink("lockred.png", true, $size);
8661  else if ($this->archiveid != 0) return $action->parent->getImageLink("archive.png", true, $size);
8662  else if ($this->control("edit") != "") return $action->parent->getImageLink("nowrite.png", true, $size);
8663  else return $action->parent->getImageLink("1x1.gif");
8664  }
8665  /**
8666  * use only for paramRefresh in attribute definition of a family
8667  * @param string $a
8668  * @param string $b
8669  * @param string $c
8670  * @return string
8671  */
8672  function nothing(
8673  /* @noinspection PhpUnusedParameterInspection */
8674  $a = "", $b = "", $c = "")
8675  {
8676  return "";
8677  }
8678  /**
8679  * return application parameter value
8680  * @deprecated use instead getParam global function or parameterManager
8681  * @see Doc::parameterManager
8682  * @param string $param parameter
8683  * @param string $defv default return value
8684  * @return string returns parameter value ou default value
8685  */
8686  final public function getParam($param, $defv = "")
8687  {
8689  return getParam($param, $defv);
8690  }
8691  //----------------------------------------------------------------------
8692  // USUAL METHODS USE FOR CALCULATED ATTRIBUTES OR FUNCTION SEARCHES
8693  //----------------------------------------------------------------------
8694  // ALL THESE METHODS NAME MUST BEGIN WITH 'GET'
8695 
8696  /**
8697  * return title of document in latest revision
8698  * @param string $id identifier of document
8699  * @param string $def default value if document not found
8700  * @return string
8701  */
8702  final public function getLastTitle($id = "-1", $def = "")
8703  {
8704  return $this->getTitle($id, $def, true);
8705  }
8706  /**
8707  * return title of document
8708  * @api get document's title
8709  * @param string $id identifier of document (if not set use current document)
8710  * @param string $def default value if document not found
8711  * @param boolean $latest search title in latest revision
8712  * @return string
8713  * @see Doc::getCustomTitle()
8714  */
8715  final public function getTitle($id = "-1", $def = "", $latest = false)
8716  {
8717  if (is_array($id)) return $def;
8718  if ($id == "") return $def;
8719  if ($id == "-1") {
8720  if ($this->locked != - 1 || (!$latest)) {
8721  if ($this->isConfidential()) return _("confidential document");
8722  return $this->getCustomTitle();
8723  } else {
8724  // search latest
8725  $id = $this->getLatestId();
8726  }
8727  }
8728  if ((strpos($id, "\n") !== false) || (strpos($id, "<BR>") !== false)) {
8729  $tid = explode("\n", str_replace("<BR>", "\n", $id));
8730  $ttitle = array();
8731  foreach ($tid as $idone) {
8732  $ttitle[] = $this->getTitle($idone, $def, $latest);
8733  }
8734  return implode("\n", $ttitle);
8735  } else {
8736  if (!is_numeric($id)) $id = getIdFromName($this->dbaccess, $id);
8737  if ($id > 0) {
8739  if (!$title) return " "; // delete title
8740  return $title;
8741  }
8742  }
8743  return $def;
8744  }
8745  /**
8746  * Same as ::getTitle()
8747  * the < & > characters as replace by entities
8748  * @param string $id docuemnt identifier to set else use current document title
8749  * @param string $def default value if document not found
8750  * @param bool $latest force use latest revision of document
8751  * @see Doc::getTitle
8752  * @return string
8753  */
8754  function getHTMLTitle($id = "-1", $def = "", $latest = false)
8755  {
8756  $t = $this->getTitle($id, $def, $latest);
8757  return $this->htmlEncode($t);
8758  }
8759  /**
8760  * the < > & characters as replace by entities
8761  * @static
8762  * @param $s
8763  * @return mixed
8764  */
8765  public static function htmlEncode($s)
8766  {
8767  $s = htmlspecialchars($s, ENT_QUOTES);
8768  return str_replace("[", "&#091;", $s);
8769  }
8770  /**
8771  * return the today date with european format DD/MM/YYYY
8772  *
8773  * @searchLabel today
8774  * @searchType date
8775  * @searchType timestamp
8776  * @api get date
8777  * @param int $daydelta to have the current date more or less day (-1 means yesterday, 1 tomorrow)
8778  * @param int|string $dayhour hours of day
8779  * @param int|string $daymin minutes of day
8780  * @param bool $getlocale whether to return locale date or not
8781  * @return string YYYY-MM-DD or DD/MM/YYYY (depend of CORE_LCDATE parameter) or locale dateDD/MM/YYYY or locale date
8782  */
8783  public static function getDate($daydelta = 0, $dayhour = "", $daymin = "", $getlocale = false)
8784  {
8785  $delta = abs(intval($daydelta));
8786  if ($daydelta > 0) {
8787  $nd = strtotime("+$delta day");
8788  } else if ($daydelta < 0) {
8789  $nd = strtotime("-$delta day");
8790  } else {
8791  $nd = time();
8792  }
8793  if ($dayhour !== "" || $daymin !== "") {
8794  $delta = abs(intval($dayhour));
8795  if ($dayhour > 0) {
8796  $nd = strtotime("+$delta hour", $nd);
8797  } else if ($dayhour < 0) {
8798  $nd = strtotime("-$delta hour", $nd);
8799  }
8800  $delta = abs(intval($daymin));
8801  if ($daymin > 0) {
8802  $nd = strtotime("+$delta min", $nd);
8803  } else if ($daymin < 0) {
8804  $nd = strtotime("-$delta min", $nd);
8805  }
8806 
8807  if ($getlocale) {
8808  return stringDateToLocaleDate(date("Y-m-d H:i", $nd));
8809  } else {
8810  return date("Y-m-d H:i", $nd);
8811  }
8812  } else {
8813  if ($getlocale) {
8814  return stringDateToLocaleDate(date("Y-m-d", $nd));
8815  } else {
8816  return date("Y-m-d", $nd);
8817  }
8818  }
8819  }
8820  /**
8821  * return the today date and time with european format DD/MM/YYYY HH:MM
8822  * @param int $hourdelta to have the current date more or less hour (-1 means one hour before, 1 one hour after)
8823  * @param bool $second if true format DD/MM/YYYY HH:MM
8824  * @return string DD/MM/YYYY HH:MM or YYYY-MM-DD HH:MM (depend of CORE_LCDATE parameter)
8825  */
8826  public static function getTimeDate($hourdelta = 0, $second = false)
8827  {
8828  $delta = abs(intval($hourdelta));
8829  if ($second) $format = "Y-m-d H:i:s";
8830  else $format = "Y-m-d H:i";
8831  if ($hourdelta > 0) {
8832  if (is_float($hourdelta)) {
8833  $dm = intval((abs($hourdelta) - $delta) * 60);
8834  return date($format, strtotime("+$delta hour $dm minute"));
8835  } else return date($format, strtotime("+$delta hour"));
8836  } else if ($hourdelta < 0) {
8837  if (is_float($hourdelta)) {
8838  $dm = intval((abs($hourdelta) - $delta) * 60);
8839  return date($format, strtotime("-$delta hour $dm minute"));
8840  } else return date($format, strtotime("-$delta hour"));
8841  }
8842  return date($format);
8843  }
8844  /**
8845  * Return the related value by linked attributes starting from referenced document.
8846  *
8847  * Can be used to retrieve a value by traversing multiple docid.
8848  *
8849  * For example,
8850  * @code
8851  * $val = $this->getDocValue("id", "id1:id2:id3")
8852  * @endcode
8853  * is a shortcut for
8854  * @code
8855  * $doc = new_Doc('', "id");
8856  * $val = $doc->getRValue("id1:id2:id3");
8857  * @endcode
8858  *
8859  * @warning
8860  * Each of the traversed docid **must** be a docid or an account, and **must not** be multiple.\n
8861  * Elsewhere, the returned value is $def
8862  * @endwarning
8863  * @see Doc::getRValue
8864  * @param int $docid document identifier
8865  * @param string $attrid attributes identifier chain (separated by ':')
8866  * @param string $def $def default return value
8867  * @param bool $latest always last revision of document
8868  * @return array|string
8869  */
8870  final public function getDocValue($docid, $attrid, $def = " ", $latest = false)
8871  {
8872  if ((!is_numeric($docid)) && ($docid != "")) {
8873  $docid = getIdFromName($this->dbaccess, $docid);
8874  }
8875  if (intval($docid) > 0) {
8876  if (strpos(':', $attrid) === false) {
8877  $attrid = strtolower($attrid);
8878  if ($latest) {
8879  $rawDoc = getTDoc($this->dbaccess, $docid, array() , array(
8880  "initid",
8881  "id",
8882  "locked",
8883  $attrid
8884  ));
8885  if ($rawDoc["locked"] == - 1) {
8886  $docid = getLatestDocId($this->dbaccess, $rawDoc["initid"]);
8887  $rawDoc = getTDoc($this->dbaccess, $docid, array() , array(
8888  $attrid
8889  ));
8890  }
8891  } else {
8892  $rawDoc = getTDoc($this->dbaccess, $docid, array() , array(
8893  $attrid
8894  ));
8895  }
8896  if ($rawDoc) {
8897  return $rawDoc[$attrid];
8898  }
8899  } else {
8900  $doc = new_Doc($this->dbaccess, $docid);
8901  if ($doc->isAlive()) {
8902  if ($latest && ($doc->locked == - 1)) {
8903  $ldocid = $doc->getLatestId();
8904  if ($ldocid != $doc->id) $doc = new_Doc($this->dbaccess, $ldocid);
8905  }
8906  return $doc->getRValue($attrid, $def, $latest);
8907  }
8908  }
8909  }
8910  return "";
8911  }
8912  /**
8913  * return value of an property for the document referenced
8914  * @see Doc::getPropertyValue
8915  * @param int $docid document identifier
8916  * @param string $propid property identifier
8917  * @param bool $latest always last revision of document if true
8918  * @return string
8919  */
8920  final public function getDocProp($docid, $propid, $latest = false)
8921  {
8922  if (intval($docid) > 0) {
8923  if ($latest) $tdoc = getTDoc($this->dbaccess, $docid);
8924  else $tdoc = getLatestTDoc($this->dbaccess, $docid);
8925  return $tdoc[strtolower($propid) ];
8926  }
8927  return "";
8928  }
8929  /**
8930  * return the current user display name
8931  * @param bool $withfirst if true compose first below last name
8932  * @return string
8933  */
8934  public static function getUserName($withfirst = false)
8935  {
8936  global $action;
8937  if ($withfirst) return $action->user->firstname . " " . $action->user->lastname;
8938  return $action->user->lastname;
8939  }
8940  /**
8941  * return the user document identifier associated to the current account
8942  * @return int
8943  */
8944  public static function userDocId()
8945  {
8946  global $action;
8947  if ($action) {
8948  return $action->user->fid;
8949  }
8950  return 0;
8951  }
8952  /**
8953  * alias for Doc::userDocId
8954  * @searchLabel My user account id
8955  * @searchType account
8956  * @searchType docid("IUSER")
8957  *
8958  * @return int
8959  */
8960  public static function getUserId()
8961  {
8962  return Doc::userDocId();
8963  }
8964  /**
8965  * return system user id
8966  * @deprecated use getSystemUserId instead
8967  * @return int
8968  */
8969  public static function getWhatUserId()
8970  {
8972 
8973  return self::getSystemUserId();
8974  }
8975  /**
8976  * return system user id
8977  * @searchLabel My system user id
8978  * @searchType uid
8979  * @return string the numeric system identifier of user
8980  */
8981  public static function getSystemUserId()
8982  {
8983  global $action;
8984  return $action->user->id;
8985  }
8986  /**
8987  * return a specific attribute of the current user document
8988  * @searchLabel account attribute
8989  * @param string $idattr attribute identifier
8990  * @return int
8991  */
8992  final public function getMyAttribute($idattr)
8993  {
8994  $mydoc = new_Doc($this->dbaccess, $this->getUserId());
8995 
8996  return $mydoc->getRawValue($idattr);
8997  }
8998  /**
8999  * concatenate and format string
9000  * to be use in computed attribute
9001  * @param string $fmt like sprintf format
9002  * @return string the composed string
9003  */
9004  function formatString($fmt)
9005  {
9006  $nargs = func_num_args();
9007 
9008  if ($nargs < 1) return "";
9009  $fmt = func_get_arg(0);
9010  $sp = array();
9011  for ($ip = 1; $ip < $nargs; $ip++) {
9012  $vip = func_get_arg($ip);
9013  if (gettype($vip) != "array") {
9014  $sp[] = $vip;
9015  }
9016  }
9017  $r = vsprintf($fmt, $sp);
9018  return $r;
9019  }
9020  /**
9021  * update internal vault index relation table
9022  * Delete temporary file property
9023  */
9024  public function updateVaultIndex()
9025  {
9026  if (empty($this->id)) return;
9027  $dvi = new DocVaultIndex($this->dbaccess);
9028 
9029  $point = uniqid("dcp:updateVaultIndex");
9030  $this->savePoint($point);
9031  $this->lockPoint($this->initid, "UPVI");
9032  // Need to lock to avoid constraint errors when concurrent docvaultindex update
9033  $dvi->DeleteDoc($this->id);
9034 
9036 
9037  $vids = array();
9038  foreach ($tvid as $vid) {
9039  if ($vid > 0) {
9040  $dvi->docid = $this->id;
9041  $dvi->vaultid = $vid;
9042  $dvi->Add();
9043  $vids[] = intval($vid);
9044  }
9045  }
9046  $this->commitPoint($point);
9047  if (count($vids) > 0) {
9049  }
9050  }
9051  // ===================
9052  // Timer Part
9053 
9054  /**
9055  * attach timer to a document
9056  * @param \Dcp\Family\TIMER &$timer the timer document
9057  * @param Doc &$origin the document which comes from the attachement
9058  * @param string $execdate date to execute first action YYYY-MM-DD HH:MM:SS
9059  * @api Attach timer to a document
9060  * @return string error - empty if no error -
9061  */
9062  final public function attachTimer(&$timer, $origin = null, $execdate = null)
9063  {
9064  $dyn = false;
9065  if ($execdate == null) {
9066  $dyn = trim(strtok($timer->getRawValue("tm_dyndate") , " "));
9067  if ($dyn) {
9068  $execdate = $this->getRawValue($dyn);
9069  if (empty($execdate)) {
9070  $execdate = '';
9071  }
9072  }
9073  }
9074  if (method_exists($timer, 'attachDocument')) {
9075  $err = $timer->attachDocument($this, $origin, $execdate);
9076  if ($err == "") {
9077  if ($dyn) $this->addATag("DYNTIMER");
9078  $this->addHistoryEntry(sprintf(_("attach timer %s [%d]") , $timer->title, $timer->id) , DocHisto::NOTICE);
9079  $this->addLog("attachtimer", array(
9080  "timer" => $timer->id
9081  ));
9082  }
9083  } else {
9084  $err = sprintf(_("attachTimer : the timer parameter is not a document of TIMER family"));
9085  }
9086  return $err;
9087  }
9088  /**
9089  * unattach timer of a document
9090  * @param \Dcp\Family\TIMER &$timer the timer document
9091  * @api Unattach timer of a document
9092  * @return string error - empty if no error -
9093  */
9094  final public function unattachTimer(&$timer)
9095  {
9096  if (method_exists($timer, 'unattachDocument')) {
9097  $err = $timer->unattachDocument($this);
9098  if ($err == "") {
9099  $this->addHistoryEntry(sprintf(_("unattach timer %s [%d]") , $timer->title, $timer->id) , DocHisto::NOTICE);
9100  $this->addLog("unattachtimer", array(
9101  "timer" => $timer->id
9102  ));
9103  }
9104  } else $err = sprintf(_("unattachTimer : the timer parameter is not a document of TIMER family"));
9105  return $err;
9106  }
9107  /**
9108  * Recompute timer's delay for all attached dynamic timers
9109  */
9110  final public function resetDynamicTimers()
9111  {
9112  $tms = $this->getAttachedTimers();
9113  if (count($tms) == 0) {
9114  $this->delATag("DYNTIMER");
9115  } else {
9116  foreach ($tms as $k => $v) {
9117  /**
9118  * @var Dcp\Family\Timer $t
9119  */
9120  $t = new_doc($this->dbaccess, $v["timerid"]);
9121  if ($t->isAlive()) {
9122  $dynDateAttr = trim(strtok($t->getRawValue("tm_dyndate") , " "));
9123  if ($dynDateAttr) {
9124  $execdate = $this->getRawValue($dynDateAttr);
9125  $previousExecdate = $this->getOldRawValue($dynDateAttr);
9126  // detect if need reset timer : when date has changed
9127  if ($previousExecdate !== false && ($execdate != $previousExecdate)) {
9128  if ($v["originid"]) $ori = new_doc($this->dbaccess, $v["originid"]);
9129  else $ori = null;
9130  $this->unattachTimer($t);
9131  $this->attachTimer($t, $ori);
9132  }
9133  }
9134  } else {
9135  $this->unattachTimer($t);
9136  }
9137  }
9138  }
9139  }
9140  /**
9141  * unattach several timers to a document
9142  * @param Doc &$origin if set unattach all timer which comes from this origin
9143  * @api Unattach all times of the document
9144  * @return string error - empty if no error -
9145  */
9146  final public function unattachAllTimers($origin = null)
9147  {
9148  /**
9149  * @var \Dcp\Family\TIMER $timer
9150  */
9151  $timer = createTmpDoc($this->dbaccess, "TIMER");
9152  $c = 0;
9153  $err = $timer->unattachAllDocument($this, $origin, $c);
9154  if ($err == "" && $c > 0) {
9155  if ($origin) $this->addHistoryEntry(sprintf(_("unattach %d timers associated to %s") , $c, $origin->title) , DocHisto::NOTICE);
9156  else $this->addHistoryEntry(sprintf(_("unattach all timers [%s]") , $c) , DocHisto::NOTICE);
9157  $this->addLog("unattachtimer", array(
9158  "timer" => "all",
9159  "number" => $c
9160  ));
9161  }
9162  return $err;
9163  }
9164  /**
9165  * return all activated document timer
9166  * @api Get all timer attached to the document
9167  * @return array of doctimer values
9168  */
9169  final public function getAttachedTimers()
9170  {
9171  include_once ("Class.QueryDb.php");
9172  include_once ("Class.DocTimer.php");
9173  $q = new QueryDb($this->dbaccess, "doctimer");
9174  $q->AddQuery("docid=" . $this->initid);
9175  $q->AddQuery("donedate is null");
9176  $l = $q->Query(0, 0, "TABLE");
9177 
9178  if (is_array($l)) return $l;
9179  return array();
9180  }
9181  /**
9182  * get all domains where document is attached by current user
9183  * @param boolean $user is set to false list all domains (independant of current user)
9184  * @param boolean $folderName is set to true append also folder name
9185  * @return array id
9186  */
9187  public function getDomainIds($user = true, $folderName = false)
9188  {
9189  if (file_exists("OFFLINE/Class.DomainManager.php")) {
9190  include_once ("FDL/Class.SearchDoc.php");
9191  $s = new searchDoc($this->dbaccess, "OFFLINEFOLDER");
9192  $s->join("id = fld(dirid)");
9193  $s->addFilter("fld.childid = %d", $this->initid);
9194  $uid = $this->getUserId();
9195  if ($user) $s->addFilter("off_user = '%d' or off_user is null", $uid);
9196  $s->overrideViewControl();
9197  $t = $s->search();
9198  $ids = array();
9199  foreach ($t as $v) {
9200  $ids[] = $v['off_domain'];
9201  if ($folderName && ((!$user) || ($v['off_user'] == $uid))) {
9202  $ids[] = $v["name"];
9203  }
9204  }
9205  return array_unique($ids);
9206  }
9207  return null;
9208  }
9209  /**
9210  * attach lock to specific domain.
9211  * @param int $domainId domain identifier
9212  * @param int $userid system user's id
9213  * @return string error message
9214  */
9215  public function lockToDomain($domainId, $userid = 0)
9216  {
9217  if (!$userid) $userid = $this->userid;
9218 
9219  if ($domainId != '') {
9220  /*
9221  * Memorize current core lock and lock document
9222  */
9223  if ($this->lockdomainid != $domainId) {
9224  /*
9225  * Memorize current core lock if lockdomain changes
9226  */
9227  $this->addUTag(1, 'LOCKTODOMAIN_LOCKED', $this->locked);
9228  }
9229  $err = $this->lock(false, $userid);
9230  if ($err != '') {
9231  return $err;
9232  }
9233  } else {
9234  /*
9235  * Restore core lock
9236  */
9237  $tag = $this->getUTag('LOCKTODOMAIN_LOCKED', true, 1);
9238  if ($tag !== false) {
9239  $this->delUTag(1, 'LOCKTODOMAIN_LOCKED');
9240  $this->locked = $tag->comment;
9241  $err = $this->modify(true, array(
9242  "locked"
9243  ) , true);
9244  if ($err != '') {
9245  return $err;
9246  }
9247  }
9248  }
9249  /*
9250  * Set or remove domain's lock
9251  */
9252  $this->lockdomainid = $domainId;
9253  $err = $this->modify(true, array(
9254  "lockdomainid"
9255  ) , true);
9256  return $err;
9257  }
9258  /**
9259  * return folder where document is set into
9260  * @return array of folder identifiers
9261  */
9262  public function getParentFolderIds()
9263  {
9264  $fldids = array();
9265  simpleQuery($this->dbaccess, sprintf("select dirid from fld where qtype='S' and childid=%d", $this->initid) , $fldids, true, false);
9266  return $fldids;
9267  }
9268  /**
9269  * update Domain list
9270  */
9271  public function updateDomains()
9272  {
9273  $domains = $this->getDomainIds(false, true);
9274  //delete domain lock if is not in the list
9275  $this->domainid = trim($this->arrayToRawValue($domains));
9276  if ($this->lockdomainid) {
9277  if (!in_array($this->lockdomainid, $domains)) $this->lockdomainid = '';
9278  else {
9279  if ($this->locked > 0) {
9280  simpleQuery($this->dbaccess, sprintf("select id from users where id=%d", $this->locked) , $lockUserId, true, true);
9281 
9282  if ($lockUserId && (!$this->isInDomain(true, $lockUserId))) {
9283  $this->lockdomainid = '';
9284  }
9285  }
9286  }
9287  }
9288 
9289  $this->modify(true, array(
9290  "domainid",
9291  "lockdomainid"
9292  ) , true);
9293  }
9294  /**
9295  * verify is doc is set in a domain
9296  * @param boolean $user limit domains where user as set document
9297  * @param string $userId another user's id else current user
9298  * @return bool
9299  */
9300  public function isInDomain($user = true, $userId = '')
9301  {
9302  if ($user) {
9303  global $action;
9304  if (!$userId) $userId = $action->user->id;
9305  if (preg_match('/_' . $userId . '$/m', $this->domainid)) return true;
9306  return false;
9307  } else {
9308  return (!empty($this->domainid));
9309  }
9310  }
9311  /**
9312  * Parse a zone string "FOO:BAR[-1]:B:PDF?k1=v1,k2=v2" into an array:
9313  *
9314  * array(
9315  * 'fulllayout' => 'FOO:BAR[-1]:B:PDF',
9316  * 'args' => 'k1=v1,k2=v2',
9317  * 'argv' => array(
9318  * 'k1' => 'v1',
9319  * 'k2' => 'v2
9320  * ),
9321  * 'app' => 'FOO',
9322  * 'layout' => 'BAR',
9323  * 'index' => '-1',
9324  * 'modifier' => 'B',
9325  * 'transform' => 'PDF'
9326  * )
9327  *
9328  * @param zone string "APP:LAYOUT:etc." $zone
9329  * @return bool|array false on error or an array containing the components
9330  */
9331  static public function parseZone($zone)
9332  {
9333  $p = array();
9334  // Separate layout (left) from args (right)
9335  $split = preg_split('/\?/', $zone, 2);
9336  $left = $split[0];
9337  if (count($split) > 1) $right = $split[1];
9338  else $right = '';
9339  // Check that the layout part has al least 2 elements
9340  $el = preg_split('/:/', $left);
9341  if (count($el) < 2) {
9342  return false;
9343  }
9344  $p['fulllayout'] = $left;
9345  $p['index'] = - 1;
9346  // Parse args into argv (k => v)
9347  if ($right != "") {
9348  $p['args'] = $right;
9349  $argList = preg_split('/&/', $p['args']);
9350  $p['argv'] = array();
9351  foreach ($argList as $arg) {
9352  $split = preg_split('/=/', $arg, 2);
9353  $left = urldecode($split[0]);
9354  $right = urldecode($split[1]);
9355  $p['argv'][$left] = $right;
9356  }
9357  }
9358  // Parse layout
9359  $parts = array(
9360  0 => 'app',
9361  1 => 'layout',
9362  2 => 'modifier',
9363  3 => 'transform'
9364  );
9365  foreach ($parts as $aPart) $p[$aPart] = null;
9366  $match = array();
9367  $i = 0;
9368  while ($i < count($el)) {
9369  if (!array_key_exists($i, $parts)) {
9370  error_log(__CLASS__ . "::" . __FUNCTION__ . " " . sprintf("Unexpected part '%s' in zone '%s'.", $el[$i], $zone));
9371  return false;
9372  }
9373  // Extract index from 'layout' part if present
9374  if ($i == 1 && preg_match("/^(?P<name>.*?)\[(?P<index>-?\d)\]$/", $el[$i], $match)) {
9375  $p[$parts[$i]] = $match['name'];
9376  $p['index'] = $match['index'];
9377  $i++;
9378  continue;
9379  }
9380  // Store part
9381  $p[$parts[$i]] = $el[$i];
9382  $i++;
9383  }
9384 
9385  return $p;
9386  }
9387  /**
9388  * Get the helppage document associated to the document family.
9389  * @param string $fromid get the helppage for this family id (default is the family of the current document)
9390  * @return \Dcp\Family\HELPPAGE the helppage document on success, or a non-alive document if no helppage is associated with the family
9391  */
9392  public function getHelpPage($fromid = "")
9393  {
9394  if ($fromid === "") {
9396  }
9397  $s = new SearchDoc($this->dbaccess, "HELPPAGE");
9398  $s->addFilter("help_family='%d'", $fromid);
9399  $help = $s->search();
9400  $helpId = "";
9401  if ($s->count() > 0) {
9402  $helpId = $help[0]["id"];
9403  }
9404  /** @noinspection PhpIncompatibleReturnTypeInspection */
9405  return new_Doc($this->dbaccess, $helpId);
9406  }
9407  /**
9408  * Get the list of compatible search methods for a given attribute type
9409  * @param string $attrId attribute name
9410  * @param string $attrType empty string to returns all methods or attribute type (e.g. 'date', 'docid', 'docid("IUSER")', etc.) to restrict search to methods supporting this type
9411  * @return array list of array('method' => '::foo()', 'label' => 'Foo Bar Baz')
9412  */
9413  public function getSearchMethods(
9414  /* @noinspection PhpUnusedParameterInspection */
9415  $attrId, $attrType = '')
9416  {
9417  include_once ('FDL/Lib.Attr.php');
9418  /*
9419  * @var Action $action
9420  */
9421  global $action;
9422  // Strip format strings for non-docid types
9423  $pType = parseType($attrType);
9424  if ($pType['type'] != 'docid') {
9425  $attrType = $pType['type'];
9426  }
9427 
9428  $collator = new Collator($action->GetParam('CORE_LANG', 'fr_FR'));
9429 
9430  $compatibleMethods = array();
9431 
9432  if ($attrType == 'date' || $attrType == 'timestamp') {
9433  $compatibleMethods = array_merge($compatibleMethods, array(
9434  array(
9435  'label' => _("yesterday") ,
9436  'method' => '::getDate(-1)'
9437  ) ,
9438  array(
9439  'label' => _("tomorrow") ,
9440  'method' => '::getDate(1)'
9441  )
9442  ));
9443  }
9444 
9445  try {
9446  $rc = new ReflectionClass(get_class($this));
9447  }
9448  catch(Exception $e) {
9449  return $compatibleMethods;
9450  }
9451 
9452  $methods = array_filter($rc->getMethods() , function ($aMethod)
9453  {
9454  /*
9455  * @var ReflectionMethod $aMethod
9456  */
9457  $methodName = $aMethod->getName();
9458  return ($aMethod->isPublic() && $methodName != '__construct');
9459  });
9460  /*
9461  * @var ReflectionMethod[] $methods
9462  */
9463  foreach ($methods as $method) {
9464  $tags = self::getDocCommentTags($method->getDocComment());
9465 
9466  $searchLabel = null;
9467  $searchTypes = array();
9468 
9469  foreach ($tags as $tag) {
9470  if ($tag['name'] == 'searchLabel') {
9471  $searchLabel = $tag['value'];
9472  } elseif ($tag['name'] == 'searchType') {
9473  $searchTypes[] = $tag['value'];
9474  }
9475  }
9476 
9477  if ($searchLabel === null) {
9478  continue;
9479  }
9480 
9481  if ($attrType == '' || in_array($attrType, $searchTypes)) {
9482  $compatibleMethods[] = array(
9483  'label' => _($searchLabel) ,
9484  'method' => sprintf('::%s()', $method->getName())
9485  );
9486  }
9487  }
9488 
9489  usort($compatibleMethods, function ($a, $b) use ($collator)
9490  {
9491  /*
9492  * @var Collator $collator
9493  */
9494  return $collator->compare($a['label'], $b['label']);
9495  });
9496 
9497  return $compatibleMethods;
9498  }
9499  /**
9500  * Check if a specific method from a specific class is a valid search method
9501  *
9502  * @param string|object $className the class name
9503  * @param string $methodName the method name
9504  * @return bool boolean 'true' if valid, boolean 'false' is not valid
9505  */
9506  public function isValidSearchMethod($className, $methodName)
9507  {
9508  if (is_object($className)) {
9509  $className = get_class($className);
9510  }
9511  try {
9512  $rc = new ReflectionClass($className);
9513  $method = $rc->getMethod($methodName);
9514  $tags = self::getDocCommentTags($method->getDocComment());
9515 
9516  foreach ($tags as $tag) {
9517  if ($tag['name'] == 'searchLabel') {
9518  return true;
9519  }
9520  }
9521  }
9522  catch(Exception $e) {
9523  return false;
9524  }
9525  return false;
9526  }
9527  /**
9528  * Extract tags names/values from methods doc comments text
9529  * @static
9530  * @param string $docComment the doc comment text
9531  * @return array|null list of array('name' => $tagName, 'value' => $tagValue)
9532  */
9533  final private static function getDocCommentTags($docComment = '')
9534  {
9535  if (!preg_match_all('/^.*?@(?P<name>[a-zA-Z0-9_-]+)\s+(?P<value>.*?)\s*$/m', $docComment, $tags, PREG_SET_ORDER)) {
9536  return array();
9537  }
9538  $tags = array_map(function ($tag)
9539  {
9540  return array(
9541  'name' => $tag['name'],
9542  'value' => $tag['value']
9543  );
9544  }
9545  , $tags);
9546  return $tags;
9547  }
9548  /**
9549  * Parse a docid's single or multiple value and resolve logical name references
9550  *
9551  * The function can report unknown logical names and can take an additional list of
9552  * known logical names to not report
9553  * @param NormalAttribute $oattr
9554  * @param string $avalue docid's raw value
9555  * @param array $unknownLogicalNames Return list of unknown logical names
9556  * @param array $knownLogicalNames List of known logical names that should not be reported as unknown in $unknownLogicalNames
9557  * @return int|string The value with logical names replaced by their id
9558  */
9559  public function resolveDocIdLogicalNames(NormalAttribute & $oattr, $avalue, &$unknownLogicalNames = array() , &$knownLogicalNames = array())
9560  {
9561  $res = $avalue;
9562  if (!is_numeric($avalue)) {
9563  if ((!strstr($avalue, "<BR>")) && (!strstr($avalue, "\n"))) {
9564  if ($oattr->getOption("docrev", "latest") == "latest") {
9565  $res = getInitidFromName($avalue);
9566  } else {
9567  $res = getIdFromName($this->dbaccess, $avalue);
9568  }
9569  if ($res == '' && !in_array($avalue, $knownLogicalNames)) {
9570  $unknownLogicalNames[] = $avalue;
9571  }
9572  } else {
9573  $tnames = explode("\n", $avalue);
9574 
9575  $tids = array();
9576  foreach ($tnames as $lname) {
9577  $mids = explode("<BR>", $lname);
9578  $tlids = array();
9579  foreach ($mids as $llname) {
9580  if (!is_numeric($llname)) {
9581  if ($oattr->getOption("docrev", "latest") == "latest") {
9582  $llid = getInitidFromName($llname);
9583  } else {
9584  $llid = getIdFromName($this->dbaccess, $llname);
9585  }
9586  if ($llid == '' && !in_array($llname, $knownLogicalNames)) {
9587  $unknownLogicalNames[] = $llname;
9588  }
9589  $tlids[] = $llid ? $llid : $llname;
9590  } else {
9591  $tlids[] = $llname;
9592  }
9593  }
9594  $tids[] = implode('<BR>', $tlids);
9595  }
9596 
9597  $res = implode("\n", $tids);
9598  }
9599  }
9600  return $res;
9601  }
9602  /**
9603  * get display values for general searches
9604  *
9605  * @param bool $withLocale use all defined locale
9606  * @return string
9607  * @throws \Dcp\Core\Exception
9608  * @throws \Dcp\Exception
9609  * @throws \Dcp\Fmtc\Exception
9610  *
9611  */
9612  protected function getExtraSearchableDisplayValues($withLocale = true)
9613  {
9614 
9615  $moreSearchValues = [];
9616 
9617  $fmt = new \FormatCollection($this);
9618  $attributes = $this->getNormalAttributes();
9619  $datesValues = [];
9620  $oneAttributeAtLeast = false;
9621  foreach ($attributes as $attr) {
9622  if ($attr->type !== "array" && $attr->getOption("searchcriteria") !== "hidden" && $this->getRawValue($attr->id)) {
9623  $fmt->addAttribute($attr->id);
9624  $oneAttributeAtLeast = true;
9625  if ($attr->type === "date") {
9626  if ($attr->isMultiple()) {
9627  $datesValues = array_merge($datesValues, $this->getMultipleRawValues($attr->id));
9628  } else {
9629  $datesValues[] = $this->getRawValue($attr->id);
9630  }
9631  }
9632  }
9633  }
9634 
9635  if ($oneAttributeAtLeast) {
9636  $datesValues = array_unique($datesValues);
9637  if ($withLocale) {
9638  $currentLocale = getParam("CORE_LANG", "fr_FR");
9639  $lang = getLocales();
9640  $locales = array_keys($lang);
9641  // set current at then end to get same locale when function finished
9642  unset($locales[$currentLocale]);
9643  $locales[] = $currentLocale;
9644  } else {
9645  $locales = array(
9646  "current"
9647  );
9648  }
9649  foreach ($locales as $klang) {
9650  if ($withLocale) {
9651  setLanguage($klang);
9652  }
9653  $moreSearchValues[] = $this->getTitle();
9654  $r = $fmt->render();
9655 
9656  foreach ($datesValues as $date) {
9657  $moreSearchValues[] = strftime("%A %B %Y %m %d", strtotime($date));
9658  }
9659  /**
9660  * @var \StandardAttributeValue $renderInfo
9661  */
9662  foreach ($r[0]["attributes"] as $renderInfo) {
9663  if (isset($renderInfo->value) && $renderInfo->displayValue !== $renderInfo->value) {
9664  $moreSearchValues[] = $renderInfo->displayValue;
9665  } elseif ($renderInfo && is_array($renderInfo)) {
9666  foreach ($renderInfo as $rowInfo) {
9667  if (isset($rowInfo->value) && $rowInfo->displayValue !== $rowInfo->value) {
9668  $moreSearchValues[] = $rowInfo->displayValue;
9669  } elseif ($rowInfo && is_array($rowInfo)) {
9670  foreach ($rowInfo as $subRowInfo) {
9671  if (isset($subRowInfo->value) && $subRowInfo->displayValue !== $subRowInfo->value) {
9672  $moreSearchValues[] = $subRowInfo->displayValue;
9673  }
9674  }
9675  }
9676  }
9677  }
9678  }
9679  }
9680  }
9681 
9682  $custom = $this->getCustomSearchValues();
9683  if ($custom) {
9684  if (!is_array($custom)) {
9685  throw new \Dcp\Exception("DOC0126", gettype($custom));
9686  }
9687  $moreSearchValues = array_merge($moreSearchValues, $custom);
9688  }
9689  return implode("£", array_unique($moreSearchValues));
9690  }
9691  /**
9692  * @api Hook to add values used in general searches
9693  * @return string
9694  */
9695  protected function getCustomSearchValues()
9696  {
9697  return [];
9698  }
9699 }
$fulltextfields
Definition: Class.Doc.php:615
Layout is a template generator.
$classname
Definition: Class.Doc.php:446
vault_properties(NormalAttribute $attr)
Definition: Class.Doc.php:8224
postInsert()
Definition: Class.Doc.php:788
getProperty($prop)
Definition: Class.Doc.php:2103
$fromname
Definition: Class.Doc.php:533
clearArrayValues($idAttr)
Definition: Class.Doc.php:3480
preEdition()
Definition: Class.Doc.php:2934
getHtmlAttrValue($attrid, $target="_self", $htmllink=2, $index=-1, $entities=true, $abstract=false)
Definition: Class.Doc.php:6489
static $infofields
Definition: Class.Doc.php:105
getOooAttrValue($attrid, $target="_self", $htmllink=false, $index=-1)
Definition: Class.Doc.php:6528
const PRESTORE_ERROR
Definition: storeInfo.php:25
preDelete()
copy($temporary=false, $control=true, $linkfld=false, $copyfile=false)
Definition: Class.Doc.php:5423
errorLogException($e)
Definition: Lib.Main.php:555
getNormalAttributes($onlyopt=false)
Definition: Class.Doc.php:2387
if(substr($wsh, 0, 1)!= '/') $args
static getUserId()
Definition: Class.Doc.php:8960
$s type
Definition: dav.php:73
$attributes
Definition: Class.Doc.php:583
unallocate($comment="", $revision=true)
Definition: Class.Doc.php:5778
nextSequence($fromid=0)
Definition: Class.Doc.php:1129
$prelid
Definition: Class.Doc.php:492
getTextualAttrValue($attrId, $index=-1, Array $configuration=array())
Definition: Class.Doc.php:6511
setState($newstate, $comment= '', $force=false, $withcontrol=true, $wm1=true, $wm2=true, $wneed=true, $wm0=true, $wm3=true, &$msg= '')
Definition: Class.Doc.php:5314
static htmlEncode($s)
Definition: Class.Doc.php:8765
$tmpfile
const HISTO_MESSAGE
$tdoc
$ldapdn
Definition: Class.Doc.php:517
setDefaultValues($tdefval, $method=true, $forcedefault=false)
Definition: Class.Doc.php:6873
$usefor
Definition: Class.Doc.php:421
sep_replace($ak, $idx, $by="-", $sep="\n")
Definition: Lib.Util.php:576
if($_POST["login"]=="")
Definition: chgpasswd.php:19
getTDoc($dbaccess, $id, $sqlfilters=array(), $result=array())
getZoneOption($zone="")
Definition: Class.Doc.php:6833
global $action
hasUTag($tag, $allrevision=true)
Definition: Class.Doc.php:4913
getLastTitle($id="-1", $def="")
Definition: Class.Doc.php:8702
newFreeVaultFile($dbaccess)
Definition: Lib.Util.php:17
fixMultipleAliveDocument(Doc &$doc)
& getAttribute($idAttr, &$oa=null, $useMask=true)
Definition: Class.Doc.php:2152
static set($key, &$item, $force=false)
latestId($fixed=false, $forcequery=false)
Definition: Class.Doc.php:2033
addUTag($uid, $tag, $datas="", $allrevision=true)
Definition: Class.Doc.php:4880
static getDate($daydelta=0, $dayhour="", $daymin="", $getlocale=false)
Definition: Class.Doc.php:8783
getOldRawValues()
Definition: Class.Doc.php:4397
preUpdate()
Definition: Class.Doc.php:932
verifyAllConstraints($stoptofirst=true, &$info=array())
Definition: Class.Doc.php:4645
addLog($code= '', $arg= '', $comment= '', $level= '', $uid= '')
Definition: Class.Doc.php:4762
$defaultedit
Definition: Class.Doc.php:727
duplicate($temporary=false, $control=true, $linkfld=false, $copyfile=false)
Definition: Class.Doc.php:5440
canLock()
Definition: Class.Doc.php:1404
getNeededAttributes($parameters=false)
Definition: Class.Doc.php:2720
getPropertyValue($prop)
Definition: Class.Doc.php:2114
stringDateToIso($date, $format=false, $withT=false)
Definition: Lib.Util.php:246
getFileAttributes($onlyfile=false)
Definition: Class.Doc.php:2528
getVersion()
Definition: Class.Doc.php:2072
vault_filename($attrid, $path=false, $index=-1)
Definition: Class.Doc.php:8176
getOldRawValue($attrid)
Definition: Class.Doc.php:4375
preAffect(array &$data, &$more, &$reset)
Definition: Class.Doc.php:1916
print< H1 > Check Database< i > $dbaccess</i ></H1 > $a
Definition: checklist.php:45
exec_query($sql, $lvl=0, $prepare=false)
postRevive()
Definition: Class.Doc.php:3052
deleteArray($idAttr)
Definition: Class.Doc.php:3508
$defDoctype
Definition: Class.Doc.php:749
PreInsert()
Definition: Class.Doc.php:864
enableEditControl()
Definition: Class.Doc.php:1157
$confidential
Definition: Class.Doc.php:511
const HISTO_INFO
getOldValue($attrid)
Definition: Class.Doc.php:4362
completeArrayRow($idAttr, $deleteLastEmptyRows=true)
Definition: Class.Doc.php:3355
print $fam getTitle() $fam name
$fields
Definition: Class.Doc.php:62
static rawValueToArray($v)
Definition: Class.Doc.php:6228
static $sqlindex
Definition: Class.Doc.php:584
getLatestId($fixed=false, $forcequery=false)
Definition: Class.Doc.php:2045
setMask($mid)
Definition: Class.Doc.php:2235
Add($nopost=false, $nopre=false)
urlWhatEncodeSpec($l)
Definition: Class.Doc.php:6215
$profid
Definition: Class.Doc.php:411
Exception class use exceptionCode to identifiy correctly exception.
Definition: exceptions.php:19
$vaultid
static getSystemUserId()
Definition: Class.Doc.php:8981
stringDateToLocaleDate($fdate, $format= '')
Definition: Lib.Util.php:98
$lmodify
Definition: Class.Doc.php:406
$archive
getDocProp($docid, $propid, $latest=false)
Definition: Class.Doc.php:8920
const CREATE_ERROR
Definition: storeInfo.php:13
$size
Definition: resizeimg.php:110
$id_fields
Definition: Class.Doc.php:607
getMainPath()
Definition: Class.Doc.php:6960
getFirstFileAttributes()
Definition: Class.Doc.php:4691
setLogicalIdentificator($name, $reset=false)
Definition: Class.Doc.php:7807
postUndelete()
Definition: Class.Doc.php:3030
getParamValue($idp, $def="")
Definition: Class.Doc.php:1522
preDuplicate(&$copyfrom)
Definition: Class.Doc.php:5502
setFile($attrid, $filename, $ftitle="", $index=-1)
Definition: Class.Doc.php:4198
hasWaitingFiles()
Definition: Class.Doc.php:2564
viewoptcard($target="_self", $ulink=true, $abstract=false)
Definition: Class.Doc.php:7872
getAValues($idAttr, $index=-1)
Definition: Class.Doc.php:3278
$paramRefresh
Definition: Class.Doc.php:757
refreshDocTitle($nameId, $nameTitle)
Definition: Class.Doc.php:8628
formatString($fmt)
Definition: Class.Doc.php:9004
getFamilyDocument()
Definition: Class.Doc.php:1482
getv(&$t, $k, $d="")
canEdit($verifyDomain=true)
Definition: Class.Doc.php:1364
$filename
addWarningMsg($msg)
Definition: Lib.Common.php:95
CanLockFile()
Definition: Class.Doc.php:1395
clearValue($attrid)
Definition: Class.Doc.php:4409
unLock($auto=false, $force=false)
Definition: Class.Doc.php:5682
getProfilAttributes()
Definition: Class.Doc.php:2469
ReallyDelete($nopost)
Definition: Class.Doc.php:1663
preRevise()
Definition: Class.Doc.php:2998
refreshUTags()
Definition: Class.Doc.php:4991
getAttachedTimers()
Definition: Class.Doc.php:9169
vaultRegisterFile($filename, $ftitle="", &$info=null)
Definition: Class.Doc.php:4173
$adate
Definition: Class.Doc.php:436
getIcon($idicon="", $size=null, $otherId=null)
Definition: Class.Doc.php:5817
Select($id)
isConfidential()
Definition: Class.Doc.php:1462
postConstructor()
Definition: Class.Doc.php:2895
$doctype
Definition: Class.Doc.php:391
getOooValue($oattr, $value, $target="_self", $htmllink=false, $index=-1)
Definition: Class.Doc.php:6548
lockToDomain($domainId, $userid=0)
Definition: Class.Doc.php:9215
specRefreshGenAttribute($attrId, $callMethod)
Definition: Class.Doc.php:5992
static getUserName($withfirst=false)
Definition: Class.Doc.php:8934
const PREGEXPFILE
Definition: Class.Doc.php:54
const LOG_NOTIFY
unArchive(&$archive)
Definition: Class.Doc.php:5598
addRevision($comment= '')
Definition: Class.Doc.php:5250
getParamAttributes()
Definition: Class.Doc.php:2515
getLatestIdWithAsk()
Definition: Class.Doc.php:5091
preCreated()
Definition: Class.Doc.php:2964
controlTdoc(&$tdoc, $aclname)
$dprofid
Definition: Class.Doc.php:485
storeFile($attrid, $filename, $ftitle="", $index=-1)
Definition: Class.Doc.php:4233
isRevisable()
Definition: Class.Doc.php:1169
$allocated
Definition: Class.Doc.php:523
getSearchMethods($attrId, $attrType= '')
Definition: Class.Doc.php:9413
preConsultation()
Definition: Class.Doc.php:2943
if($dbaccess=="") $dvi
deleteValue($attrid)
Definition: Class.Doc.php:4431
nothing($a="", $b="", $c="")
Definition: Class.Doc.php:8672
getStatelabel()
Definition: Class.Doc.php:5404
if($famId) $s
const FAM_ACCESSDOC
Definition: Class.Doc.php:31
$mimetype
Definition: geticon.php:24
getDocWithSameTitle($key1="title", $key2="")
Definition: Class.Doc.php:1592
preCopy(&$copyfrom)
Definition: Class.Doc.php:5516
viewattr($target="_self", $ulink=true, $abstract=false, $viewhidden=false)
Definition: Class.Doc.php:7695
preUndelete()
Definition: Class.Doc.php:3020
changeIcon($icon)
Definition: Class.Doc.php:5847
getArrayRawValues($idAttr, $index=-1)
Definition: Class.Doc.php:3292
static seemsMethod($method)
Definition: Class.Doc.php:4495
allocate($userid, $comment="", $revision=false, $autolock=true)
Definition: Class.Doc.php:5722
urlWhatEncode($link, $k=-1)
Definition: Class.Doc.php:6082
viewdefaultcard($target="_self", $ulink=true, $abstract=false, $viewhidden=false)
Definition: Class.Doc.php:7099
$defaultmview
Definition: Class.Doc.php:742
static getError($code, $args=null)
Definition: ErrorCode.php:27
isAffected()
$lang
Definition: lang.php:18
getParameterFamilyRawValue($idp, $def)
Definition: Class.Doc.php:1577
getLocaleConfig($core_lang= '')
Definition: Lib.Common.php:853
searchUTags($tag="", $allrevision=true, $allusers=false)
Definition: Class.Doc.php:5008
isInDomain($user=true, $userId= '')
Definition: Class.Doc.php:9300
$d
Definition: dav.php:77
getRevisionState($state, $fixed=false)
Definition: Class.Doc.php:1620
removeArrayRow($idAttr, $index)
Definition: Class.Doc.php:3328
getRValue($RidAttr, $def="", $latest=true, $html=false)
Definition: Class.Doc.php:4333
getDomainIds($user=true, $folderName=false)
Definition: Class.Doc.php:9187
getState()
Definition: Class.Doc.php:5341
$attrids
Definition: Class.Doc.php:551
setLogicalName($name, $reset=false, $verifyOnly=false)
Definition: Class.Doc.php:7823
isUTF8($string)
Definition: Lib.Common.php:748
unattachTimer(&$timer)
Definition: Class.Doc.php:9094
askIsCompleted()
Definition: Class.Doc.php:5079
refresh()
Definition: Class.Doc.php:6018
$eviews
Definition: Class.Doc.php:573
getFamilyParameterValue($idp, $def="")
Definition: Class.Doc.php:1538
setWaskAnswer($waskid, $answer)
Definition: Class.Doc.php:5064
regenerateTemplates()
Definition: Class.Doc.php:1068
getStateColor($def="")
Definition: Class.Doc.php:5359
hasPermission($aclName, $strict=false)
Definition: Class.Doc.php:6621
isAlive()
Definition: Class.Doc.php:6647
getLatestTDoc($dbaccess, $initid, $sqlfilters=array(), $fromid=false)
getCustomSearchValues()
Definition: Class.Doc.php:9695
viewproperties($target="finfo", $ulink=true, $abstract=true)
Definition: Class.Doc.php:7535
equal($a, $b)
Definition: Class.Doc.php:2777
const DEFAULT_PUBDIR
Definition: Lib.Prefix.php:28
& tag()
Definition: Class.Doc.php:2127
$defaultcreate
Definition: Class.Doc.php:737
static setTypedValue(\Doc &$doc,\NormalAttribute &$oAttr, $value)
const USEMASKCVVIEW
Definition: Class.Doc.php:60
disableEditControl()
Definition: Class.Doc.php:1146
savePoint($point)
setChanged()
Definition: Class.Doc.php:844
viewprop($target="_self", $ulink=true, $abstract=false)
Definition: Class.Doc.php:7781
getHisto($allrev=false, $code="", $limit=0)
Definition: Class.Doc.php:4798
save(&$info=null, $skipConstraint=false)
Definition: Class.Doc.php:1280
postCopy(&$copyfrom)
Definition: Class.Doc.php:5543
addParamRefresh($in, $out)
Definition: Class.Doc.php:5902
modify($nopost=false, $sfields="", $nopre=false)
refreshTitle()
Definition: Class.Doc.php:2873
setTitle($title)
Definition: Class.Doc.php:3061
$defProfFamId
Definition: Class.Doc.php:661
sendTextTransformation($dbaccess, $docid, $attrid, $index, $vid)
Definition: Lib.Vault.php:180
getCustomTitle()
Definition: Class.Doc.php:8610
getFreedomFromTitle($title)
Definition: Class.Doc.php:1496
getInitidFromName($name)
PreDocDelete()
Definition: Class.Doc.php:1647
storeFiles($attrid, $filenames, $ftitle="")
Definition: Class.Doc.php:4249
const HISTO_ERROR
getDocValue($docid, $attrid, $def=" ", $latest=false)
Definition: Class.Doc.php:8870
$order_by
Definition: Class.Doc.php:613
updateRelations($force=false)
Definition: Class.Doc.php:1100
applyMethod($method, $def="", $index=-1, array $bargs=array(), array $mapArgs=array(), &$err= '')
Definition: Class.Doc.php:4511
getFilesProperties()
Definition: Class.Doc.php:2543
editattr($withtd=true)
Definition: Class.Doc.php:8129
deleteTemporary()
Definition: Class.Doc.php:1636
convertVaultFile($va, $engine, $isimage=false)
Definition: Class.Doc.php:2615
isFixed()
Definition: Class.Doc.php:5114
addATag($tag)
Definition: Class.Doc.php:4818
$docid
Definition: cleanFamily.php:13
getFieldAttributes()
Definition: Class.Doc.php:2398
static _cmpanswers($a, $b)
Definition: Class.Doc.php:7524
addArrayRow($idAttr, $tv, $index=-1)
Definition: Class.Doc.php:3425
getFileExtension($filename)
$sqlcreate
Definition: Class.Doc.php:662
updateDomains()
Definition: Class.Doc.php:9271
$verifyOnly
Definition: cleanFamily.php:14
isValidSearchMethod($className, $methodName)
Definition: Class.Doc.php:9506
getValue($idAttr, $def="")
Definition: Class.Doc.php:3201
$tout
Definition: checklist.php:47
getLayoutFile($app, $layfile)
Definition: Lib.Common.php:258
getSqlIndex()
Definition: Class.Doc.php:6766
lockPoint($exclusiveLock, $exclusiveLockPrefix= '')
$revdate
Definition: Class.Doc.php:426
getMyAttribute($idattr)
Definition: Class.Doc.php:8992
affect($array, $more=false, $reset=true)
Definition: Class.Doc.php:1856
getLocales()
Definition: Lib.Common.php:870
$views
Definition: Class.Doc.php:416
recomputeTextFiles($aid= '')
Definition: Class.Doc.php:3890
postImport(array $extra=array())
Definition: Class.Doc.php:2987
getCurSequence()
Definition: Class.Doc.php:1112
$outfile
isChanged()
Definition: Class.Doc.php:853
changeFreeState($newstateid, $comment= '', $revision=true)
Definition: Class.Doc.php:5264
postUpdate()
Definition: Class.Doc.php:995
getHtmlInput(&$doc, &$oattr, $value, $index="", $jsevent="", $notd=false)
Definition: editutil.php:30
postModify()
Definition: Class.Doc.php:2904
editbodycard($target="_self", $ulink=true, $abstract=false, $onlyopt=false)
Definition: Class.Doc.php:7900
const CONSTRAINT_ERROR
Definition: storeInfo.php:21
isLocked($my=false)
Definition: Class.Doc.php:1449
$title
Definition: Class.Doc.php:346
regenerateTemplate($aid, $index=-1)
Definition: Class.Doc.php:1021
getDocTitle($id, $latest=true)
controlId($docid, $aclname, $strict=false)
$locked
Definition: Class.Doc.php:396
duplicateFiles()
Definition: Class.Doc.php:4286
$fromid
Definition: Class.Doc.php:366
$force
setValue($attrid, $value, $index=-1, &$kvalue=null)
Definition: Class.Doc.php:3528
viewthumbcard($target="finfo", $ulink=true, $abstract=true)
Definition: Class.Doc.php:7425
setFamidInLayout()
Definition: Class.Doc.php:8157
setProfil($profid, $fromdocidvalues=null)
isFixedDoc($dbaccess, $id)
$path
Definition: dav.php:39
setAttributeValue($idAttr, $value)
Definition: Class.Doc.php:3164
static getFileInfo($idfile, $teng_name="")
getMultipleRawValues($idAttr, $def="", $index=-1)
Definition: Class.Doc.php:3240
postAffect(array $data, $more, $reset)
Definition: Class.Doc.php:1927
getSortAttributes()
Definition: Class.Doc.php:2856
const USEMASKCVEDIT
Definition: Class.Doc.php:61
getTValue($idAttr, $def="", $index=-1)
Definition: Class.Doc.php:3221
UpdateVaultIndex($i, &$doc, &$dvi)
$state
Definition: Class.Doc.php:451
sqlTrigger($onlydrop=false, $code=false)
Definition: Class.Doc.php:6657
revision(Action &$action)
Definition: revision.php:22
delATag($tag)
Definition: Class.Doc.php:4855
createDoc($dbaccess, $fromid, $control=true, $defaultvalues=true, $temporary=false)
__toString()
Definition: Class.Doc.php:776
getEmblem($size=null)
Definition: Class.Doc.php:8645
getHttpVars($name, $def="", $scope="all")
Definition: Lib.Http.php:124
$obj_acl
Definition: Class.Doc.php:715
preRevive()
Definition: Class.Doc.php:3041
static _val2array($v)
Definition: Class.Doc.php:6240
getTextValueFromFile($attrid, &$text)
Definition: Class.Doc.php:3979
getParam($param, $defv="")
Definition: Class.Doc.php:8686
setLanguage($lang)
Definition: Lib.Common.php:886
if($updateExistingTable) $point
Definition: updateclass.php:88
getHTMLTitle($id="-1", $def="", $latest=false)
Definition: Class.Doc.php:8754
$lockdomainid
Definition: Class.Doc.php:371
getFileLink($attrid, $index=-1, $cache=false, $inline=false, $otherValue= '', $info=null)
Definition: Class.Doc.php:6293
$cdate
Definition: Class.Doc.php:431
getOldValues()
Definition: Class.Doc.php:4387
CanUnLockFile()
Definition: Class.Doc.php:1422
const UPDATE_ERROR
Definition: storeInfo.php:17
getDebugStack($slice=1)
Definition: Lib.Common.php:325
getRefreshVisibility()
Definition: Class.Doc.php:5916
attachTimer(&$timer, $origin=null, $execdate=null)
Definition: Class.Doc.php:9062
$domainid
Definition: Class.Doc.php:376
revive()
Definition: Class.Doc.php:1783
toxml($withdtd=false, $id_doc="")
Definition: Class.Doc.php:8316
isValidDate($date)
Definition: Lib.Util.php:228
getFamIdFromName($dbaccess, $name)
mb_ucfirst($s)
Definition: Lib.Common.php:105
getTitle($id="-1", $def="", $latest=false)
Definition: Class.Doc.php:8715
canUnLock()
Definition: Class.Doc.php:1412
getHtmlValue($oattr, $value, $target="_self", $htmllink=true, $index=-1, $entities=true, $abstract=false)
Definition: Class.Doc.php:6457
getInputAttributes($onlyopt=false)
Definition: Class.Doc.php:2497
postCreated()
Definition: Class.Doc.php:2953
getFileInfo($filesvalue, $key="", $returnType="array")
Definition: Class.Doc.php:8253
getUTag($tag, $allrevision=true, $uid=null)
Definition: Class.Doc.php:4934
getRevisions($type="LIST", $limit=200)
Definition: Class.Doc.php:2013
specRefresh()
Definition: Class.Doc.php:5957
static getWhatUserId()
Definition: Class.Doc.php:8969
copyFile($idattr, $newname="", $index=-1)
Definition: Class.Doc.php:4101
vault_generate($dbaccess, $engine, $vidin, $vidout, $isimage=false, $docid= '')
Definition: Lib.Vault.php:63
getChildFam($id=-1, $controlcreate=false)
Definition: Class.Doc.php:1984
preRefresh()
Definition: Class.Doc.php:5946
getTmpDir($def= '/tmp')
Definition: Lib.Common.php:150
$atags
Definition: Class.Doc.php:499
deprecatedFunction($msg= '')
Definition: Lib.Common.php:86
getCurrentUser()
Definition: Lib.Common.php:250
global $_SERVER
init_dbid()
isCompleteNeeded()
Definition: Class.Doc.php:2747
getValueMethod($value)
Definition: Class.Doc.php:4489
translate($docid, $translate)
Definition: Class.Doc.php:5550
$className
getFromDoc()
Definition: Class.Doc.php:1974
convert($fromid, $prevalues=array())
Definition: Class.Doc.php:1200
$postitid
Definition: Class.Doc.php:504
rollbackPoint($point)
getHelpPage($fromid="")
Definition: Class.Doc.php:9392
delUTags($uid=0)
Definition: Class.Doc.php:4979
$revision
Definition: Class.Doc.php:351
getMenuAttributes($viewhidden=false)
Definition: Class.Doc.php:2704
viewabstractcard($target="finfo", $ulink=true, $abstract=false)
Definition: Class.Doc.php:7644
setNameAuto($temporary=false)
Definition: Class.Doc.php:6937
new_Doc($dbaccess, $id= '', $latest=false)
viewDoc($layout="FDL:VIEWBODYCARD", $target="_self", $ulink=true, $abstract=false, $changelayout=false)
Definition: Class.Doc.php:6994
$values
Definition: Class.Doc.php:546
canUpdateDoc()
Definition: Class.Doc.php:1266
getFamilyParameter(&$action, $famid, $key, $def="")
archive(&$archive)
Definition: Class.Doc.php:5564
vault_store($filename, &$vid, $ftitle="")
Definition: Lib.Vault.php:153
description()
Definition: Class.Doc.php:1945
static userDocId()
Definition: Class.Doc.php:8944
postDuplicate(&$copyfrom)
Definition: Class.Doc.php:5529
getNameFromId($dbaccess, $id)
static parseZone($zone)
Definition: Class.Doc.php:9331
resolveDocIdLogicalNames(NormalAttribute &$oattr, $avalue, &$unknownLogicalNames=array(), &$knownLogicalNames=array())
Definition: Class.Doc.php:9559
preImport(array $extra=array())
Definition: Class.Doc.php:2976
commitPoint($point)
refreshRn()
Definition: Class.Doc.php:6040
addComment($comment= '', $level=DocHisto::INFO, $code= '', $uid= '')
Definition: Class.Doc.php:4747
& getAttributes($useMask=true)
Definition: Class.Doc.php:2174
getRssLink()
Definition: Class.Doc.php:6275
setTextValueInFile($attrid, $value, $ftitle="")
Definition: Class.Doc.php:3925
$from
parseType($type)
Definition: Lib.Attr.php:29
controlUser($uid, $aclname)
Definition: Class.Doc.php:6632
getExportAttributes($withfile=false, $forcedefault=false)
Definition: Class.Doc.php:2787
ComputeVisibility($vis, $fvis, $ffvis= '')
postDelete()
specRefreshGen($onlyspec=false)
Definition: Class.Doc.php:5979
static isWellformedLogicalName($name)
Definition: CheckDoc.php:111
getFathersDoc()
Definition: Class.Doc.php:1955
static getTimeDate($hourdelta=0, $second=false)
Definition: Class.Doc.php:8826
$sup_fields
Definition: Class.Doc.php:101
complete()
Definition: Class.Doc.php:1905
$fromtitle
Definition: Class.Doc.php:537
static getTypedValue(\Doc &$doc,\NormalAttribute &$oAttr)
resetConvertVaultFile($attrid, $index)
Definition: Class.Doc.php:2584
exportXml(&$xml, $withfile=false, $outfile="", $wident=true, $flat=false, $exportAttributes=array())
Definition: Class.Doc.php:8284
static arrayToRawValue($v, $br= '< BR >')
Definition: Class.Doc.php:6252
renameFile($idattr, $newname, $index=-1)
Definition: Class.Doc.php:4139
$vf
Definition: geticon.php:28
getSpecTitle()
Definition: Class.Doc.php:8619
$svalues
Definition: Class.Doc.php:100
postRefresh()
Definition: Class.Doc.php:5969
postRevise()
Definition: Class.Doc.php:3009
$archiveid
Definition: Class.Doc.php:529
const DELVALUE
Definition: Class.Doc.php:46
preStore()
Definition: Class.Doc.php:2925
getParentFolderIds()
Definition: Class.Doc.php:9262
affectColumn($fields, $reset=true)
init()
Definition: Class.Doc.php:1934
$info
Definition: geticon.php:30
getActionAttributes()
Definition: Class.Doc.php:2413
verifyConstraint($attrid, $index=-1)
Definition: Class.Doc.php:4600
static _array2val($v, $br= '< BR >')
Definition: Class.Doc.php:6266
if(($docid!==0)&&(!is_numeric($docid))) $query
delUTag($uid, $tag, $allrevision=true)
Definition: Class.Doc.php:4960
getIdFromName($dbaccess, $name)
getFamDoc()
Definition: Class.Doc.php:1472
$defaultabstract
Definition: Class.Doc.php:732
$defaultview
Definition: Class.Doc.php:722
simpleQuery($dbaccess, $query, &$result=array(), $singlecolumn=false, $singleresult=false, $useStrict=null)
Definition: Lib.Common.php:484
$cviews
Definition: Class.Doc.php:568
getLabel($idAttr)
Definition: Class.Doc.php:2091
getStateActivity($def="")
Definition: Class.Doc.php:5383
$comment
Definition: Class.Doc.php:441
todtd()
Definition: Class.Doc.php:8466
createTmpDoc($dbaccess, $fromid, $defaultvalue=true)
getZoneTransform($zone="")
Definition: Class.Doc.php:6851
store(&$info=null, $skipConstraint=false)
Definition: Class.Doc.php:1308
if($file) if($subject==""&&$file) if($subject=="") $err
$fulltext
Definition: Class.Doc.php:541
getValues()
Definition: Class.Doc.php:3085
addHistoryEntry($comment= '', $level=DocHisto::INFO, $code= '', $uid= '')
Definition: Class.Doc.php:4707
getTitleAttributes()
Definition: Class.Doc.php:2450
$owner
Definition: Class.Doc.php:341
lock($auto=false, $userid=0)
Definition: Class.Doc.php:5637
getDocAnchor($id, $target="_self", $htmllink=true, $title=false, $js=true, $docrev="latest", $viewIcon=false)
Definition: Class.Doc.php:6348
delete($nopost=false)
getRawValue($idAttr, $def="")
Definition: Class.Doc.php:3117
$dbtable
Definition: Class.Doc.php:611
$specialmenu
Definition: Class.Doc.php:747
getLatestDocId($dbaccess, $initid)
$param
Definition: import_size.php:31
$initid
Definition: Class.Doc.php:361
N_($s)
Definition: Lib.Common.php:18
$latest
computeDProfil($dprofid=0, $fromdocidvalues=null)
editoptcard($target="_self", $ulink=true, $abstract=false)
Definition: Class.Doc.php:7886
$value
getATag($tag)
Definition: Class.Doc.php:4844
getOption($x, $def="")
mb_trim($string)
Definition: Lib.Common.php:113
vault_filename_fromvalue($fileid, $path=false)
Definition: Class.Doc.php:8188
getImportAttributes()
Definition: Class.Doc.php:2822
controlUserId($docid, $uid, $aclname)
getDocObject($dbaccess, $v, $k=0)
getAbstractAttributes()
Definition: Class.Doc.php:2430
const MESSAGE
control($aclname, $strict=false)
Definition: Class.Doc.php:6593
postStore()
Definition: Class.Doc.php:2913
undelete()
Definition: Class.Doc.php:1794
noPrivilegeMessage(Doc &$doc, $aclname)
Definition: Class.Doc.php:6571
getZoneFile($zone)
Definition: Class.Doc.php:6793
static setFilesPersitent(array $vids)
updateVaultIndex()
Definition: Class.Doc.php:9024
const NOTICE
transfertValuesFrom(&$from)
Definition: Class.Doc.php:1183
$data
getGen($dbaccess)
Definition: Lib.Util.php:27
$version
Definition: Class.Doc.php:356
first($a)
← centre documentaire © anakeen