18 include_once (
"DATA/Class.Collection.php");
19 include_once (
"OFFLINE/Class.ExceptionCode.php");
20 include_once (
"FDL/Class.DocWaitManager.php");
33 private $domain = null;
38 private $domainApi = null;
41 $this->domain = $domain;
42 $this->domainApi = $domainApi;
44 private static function setError($err)
46 throw new Exception($err);
55 public static function isUpToDate(Doc & $doc, array & $stillRecorded)
58 if (!$stillRecorded[$doc->initid])
return false;
59 if (intval($stillRecorded[$doc->initid]->locked) != intval($doc->locked))
return false;
60 if (intval($stillRecorded[$doc->initid]->lockdomainid) != intval($doc->lockdomainid))
return false;
61 if ($stillRecorded[$doc->initid]->revdate >= $doc->revdate)
return true;
70 $err = $this->callHook(
"onBeforePullSharedDocuments");
73 $stillRecorded = array();
74 if (is_array($config->stillRecorded)) {
76 foreach ($config->stillRecorded as $record) {
77 $stillRecorded[$record->initid] = $record;
81 if ($this->domain->hook()) {
82 $domain = $this->domain;
83 $callback =
function (&$doc) use ($domain, $stillRecorded)
86 if ($isUpToDate)
return false;
87 $err = call_user_func_array(array(
89 $method =
"onPullDocument"
90 ) , array(&$domain, &$doc
93 return (empty($err) || ($err ===
true));
96 if (count($stillRecorded) > 0) {
97 $callback =
function (&$doc) use ($stillRecorded)
100 if ($isUpToDate)
return false;
105 $out = $this->domainApi->getSharedDocuments($config, $callback);
106 $out->documentsToDelete = $this->getIntersect($this->domain->getSharedFolder() , $stillRecorded);
112 $log->error = $out->error;
113 $log->documentsToDelete = $out->documentsToDelete;
114 if (is_array($out->content)) {
115 foreach ($out->content as & $rdoc) {
116 $log->documentsToUpdate[] = $rdoc[
"properties"][
"initid"];
119 $this->domain->addLog(__METHOD__, $log);
123 private function getIntersect(Dir & $folder, array & $stillRecorded)
125 $serverInitids = $folder->getContentInitid();
126 $clientInitids = array_keys($stillRecorded);
127 return array_values(array_diff($clientInitids, $serverInitids));
135 $docid = $config->docid;
136 $doc = new_doc(getDbaccess() , $docid,
true);
139 if ($doc->isAlive()) {
140 $err = $this->callHook(
"onPullDocument", $doc);
141 if ($err ==
"" || $err ===
true) {
142 $this->domain->addFollowingStates($doc);
144 $out = $this->domainApi->revertDocument($config);
149 $out->error = sprintf(_(
"document %s not found") , $docid);
152 $log->initid = $doc->initid;
153 $log->title = $doc->getTitle();
154 $log->error = $out->error;
155 $this->domain->addLog(__METHOD__, $log);
164 $docid = $config->docid;
165 $doc = new_doc(getDbaccess() , $docid,
true);
168 if ($doc->isAlive()) {
169 $out = $this->domainApi->removeUserDocument($config);
172 $out->error = sprintf(_(
"document %s not found") , $docid);
175 $log->initid = $doc->initid;
176 $log->title = $doc->getTitle();
177 $log->error = $out->error;
178 $this->domain->addLog(__METHOD__, $log);
187 $docid = $config->docid;
188 $doc = new_doc(getDbaccess() , $docid,
true);
190 if ($doc->isAlive()) {
191 $this->domain->addFollowingStates($doc);
193 $out = $this->domainApi->bookDocument($config);
196 $out->error = sprintf(_(
"document %s not found") , $docid);
199 $log->initid = $doc->initid;
200 $log->title = $doc->getTitle();
201 $log->error = $out->error;
202 $this->domain->addLog(__METHOD__, $log);
211 $docid = $config->docid;
212 $doc = new_doc(getDbaccess() , $docid,
true);
214 if ($doc->isAlive()) {
216 $this->domain->addFollowingStates($doc);
218 $out = $this->domainApi->unbookDocument($config);
221 $out->error = sprintf(_(
"document %s not found") , $docid);
224 $log->initid = $doc->initid;
225 $log->title = $doc->getTitle();
226 $log->error = $out->error;
227 $this->domain->addLog(__METHOD__, $log);
236 $err = $this->callHook(
"onBeforePullUserDocuments");
239 $stillRecorded = array();
240 if (is_array($config->stillRecorded)) {
241 foreach ($config->stillRecorded as $record) {
242 $stillRecorded[$record->initid] = $record;
245 if ($this->domain->hook()) {
246 $domain = $this->domain;
247 $callback =
function (&$doc) use ($domain, $stillRecorded)
250 if ($isUpToDate)
return false;
251 $domain->addFollowingStates($doc);
252 $err = call_user_func_array(array(
254 $method =
"onPullDocument"
255 ) , array(&$domain, &$doc
257 return (empty($err) || ($err ===
true));
260 $domain = $this->domain;
261 $callback =
function (&$doc) use ($domain, $stillRecorded)
264 if ($isUpToDate)
return false;
265 $domain->addFollowingStates($doc);
269 $out = $this->domainApi->getUserDocuments($config, $callback);
270 $out->documentsToDelete = $this->getIntersect($this->domain->getUserFolder() , $stillRecorded);
276 $log->error = $out->error;
277 $log->documentsToDelete = $out->documentsToDelete;
278 if (is_array($out->content)) {
279 foreach ($out->content as & $rdoc) {
280 $log->documentsToUpdate[] = $rdoc[
"properties"][
"initid"];
283 $this->domain->addLog(__METHOD__, $log);
293 $out->acknowledgement = $this->callHook(
"onAfterPullUserDocuments");
303 $out->acknowledgement = $this->callHook(
"onAfterPullSharedDocuments");
313 $docid = $config->docid;
316 if (preg_match(
'/(.*)\[([0-9]+)\]$/', $aid, $reg)) {
318 $aid = trim($reg[1]);
320 $path =
'php://input';
322 $tmpfile = tempnam(getTmpDir() ,
'pushFile');
323 if ($tmpfile ==
false) {
324 $err = sprintf(
"cannot create temporay file %s", $tmpfile);
326 copy($path, $tmpfile);
327 $filename = $config->filename;
329 if ($this->isLocalIdenticator($docid)) {
331 $docid = $this->numerizeId($docid);
333 $wdoc = DocWaitManager::getWaitingDoc($docid);
336 $doc = $wdoc->getWaitingDocument();
338 $oa = $doc->getAttribute($aid);
344 $doc->initid = $docid;
345 $doc->localid = $localid;
347 $err = $doc->storeFile($oa->id, $tmpfile, $filename, $index);
349 $err = DocWaitManager::saveWaitingDoc($doc, $this->domain->id, $config->transaction);
355 $this->domain->addLog(__METHOD__, $out);
365 private function raw2doc($rawdoc, &$doc)
367 $fromid = $rawdoc->properties->fromid;
368 $doc = createDoc(getDbAccess() , $fromid,
false,
false,
false);
371 $err = sprintf(
"cannot create document %s", $fromid);
374 if ($this->isNewDocument($rawdoc)) {
375 $rawdoc->properties->localid = $rawdoc->properties->id;
376 $rawdoc->properties->initid = $this->numerizeId($rawdoc->properties->id);
377 $rawdoc->properties->id = 0;
379 foreach ($rawdoc->properties as $k => $v) {
380 if (is_array($v)) $v = implode(
"\n", $v);
383 $doc->affect($props);
384 foreach ($rawdoc->values as $k => $v) {
386 $oa = $doc->getAttribute($k);
388 if ($oa->type ==
"docid") {
389 $v = $this->numerizeAllId($v);
391 if ($v ==
'') $v =
" ";
392 $serr = $doc->setValue($k, $v);
394 $err.= sprintf(
"%s : %s", $oa->getLabel() , $serr);
404 private function isNewDocument($rawdoc)
406 return $this->isLocalIdenticator($rawdoc->properties->id);
408 private function isLocalIdenticator($id)
410 if (preg_match(
'/^' . $this::newPrefix .
'/', $id))
return true;
419 $rawdoc = $config->document;
425 $extraData = $rawdoc->properties->pushextradata;
426 if ($extraData === null) {
430 if (!$this->isNewDocument($rawdoc)) {
431 $refdoc = new_doc(getDbAccess() , $rawdoc->properties->id,
true);
436 $err = $this->raw2doc($rawdoc, $doc);
440 $err = $this->callHook(
"onBeforePushDocument", $doc, $extraData);
444 $err = DocWaitManager::saveWaitingDoc($doc, $this->domain->id, $config->transaction, $extraData);
449 $message = $this->callHook(
"onAfterPushDocument", $doc, $extraData);
450 $fdoc =
new Fdl_Document($doc->id, null, $doc);
451 $out = $fdoc->getDocument(
true,
false);
452 $out[
"message"] = $message;
455 $waitDoc = DocWaitManager::getWaitingDoc($rawdoc->properties->initid);
457 $doc = new_doc(getDbAccess() , $rawdoc->properties->id,
true);
458 $err = DocWaitManager::saveWaitingDoc($doc, $this->domain->id, $config->transaction, $extraData);
460 $waitDoc->transaction = $config->transaction;
461 $waitDoc->status = $waitDoc::invalid;
462 $waitDoc->statusmessage = $err;
465 $out->error = sprintf(_(
"push:invalid document : %s") , $err);
469 $out->error = _(
"push:no document found");
472 $waitDoc = DocWaitManager::getWaitingDoc($rawdoc->properties->initid);
475 $log = (object)$waitDoc->getValues();
476 unset($log->orivalues);
481 $log->error = $out->error;
482 if (is_array($out)) {
483 $log->message = $out[
"message"];
485 $this->domain->addLog(__METHOD__, $log);
488 private function callHook($method, &$arg1 = null, &$arg2 = null, &$arg3 = null)
491 if ($this->domain->hook()) {
492 if (method_exists($this->domain->hook() , $method)) {
493 return call_user_func_array(array(
494 $this->domain->hook() ,
496 ) , array(&$this->domain, &$arg1, &$arg2, &$arg3
508 include_once (
"FDL/Class.DocWaitManager.php");
510 $err = DocWaitManager::clearWaitingDocs($this->domain->id, $this->domain->getSystemUserId());
525 $err = $this->domain->updateReport($this->domain->getSystemUserId() , $report);
527 if (!$err) $out->report = $report;
538 $err = $this->callHook(
"onBeforePushTransaction");
542 $out->transactionId = DocWaitManager::getTransaction();
544 $this->domain->addLog(__METHOD__, $out);
552 private function verifyAllConflict(DbObjectList & $waitings, &$out)
555 foreach ($waitings as $k => $waitDoc) {
556 $status = $waitDoc->computeStatus();
557 $out->detailStatus[$waitDoc->refererinitid] = array(
558 "statusMessage" => $waitDoc->statusmessage ? $waitDoc->statusmessage : _(
"verified") ,
559 "statusCode" => $waitDoc->status
561 if (!$waitDoc->isValid()) {
562 $err = $waitDoc->statusmessage;
570 if (!$this->domain->isMember())
return _(
"not a member domain");
571 $err = $doc->canEdit(
false);
575 if ($doc->lockdomainid != $this->domain->id) $err = sprintf(_(
"lock must be in domain %s") , $this->domain->getTitle());
595 private function numerizeAllId($s)
597 return preg_replace(
"/(DLID-[a-f0-9-]+)/se",
"\$this->numerizeId('\\1')", $s);
604 private function numerizeId($s)
607 if ($u < 0)
return $u;
609 if (($u >> 31) == 0)
return -($u);
610 return -round($u / 2);
616 private function updateLocalLink(&$results)
618 $details = $results->detailStatus;
620 $serverIds = array();
621 foreach ($details as $k => $v) {
622 $lid = $v[
'localId'];
624 $localIds[] = $this->numerizeId($lid);
629 $list =
new DocumentList();
630 $list->addDocumentIdentificators($serverIds);
631 foreach ($list as $id => $doc) {
632 $oas = $doc->getNormalAttributes();
634 foreach ($oas as $aid => $oa) {
635 if ($oa->type ==
"docid") {
636 $value = $doc->getValue($aid);
638 $nvalue = str_replace($localIds, $serverIds, $value);
639 if ($nvalue != $value) {
640 $doc->setValue($aid, $nvalue);
646 if ($needModify) $doc->modify();
655 if ($config->transaction) {
658 $waitings = DocWaitManager::getWaitingDocs($config->transaction);
660 $policy = $this->domain->getValue(
'off_transactionpolicy');
661 if ($policy ==
"global") {
663 $status = $this->verifyAllConflict($waitings, $out);
667 $err = $this->callHook(
"onAfterPushTransaction");
671 $out->detailStatus = array();
672 $beforeSavePoint =
"synchro" . $config->transaction;
673 if ($policy ==
"global") {
674 $this->domain->savePoint($beforeSavePoint);
677 $out->detailStatus = $this->saveWaitings($waitings);
679 $completeSuccess =
true;
681 foreach ($out->detailStatus as $aStatus) {
683 if ($aStatus[
'isValid']) {
686 $completeSuccess =
false;
691 if (count($out->detailStatus) > 0) {
692 $out->status = self::abortTransaction;
695 $out->status = self::successTransaction;
698 $out->status = $completeSuccess ? self::successTransaction : self::partialTransaction;
699 if ($completeSuccess || ($policy !=
"global")) {
700 $this->updateLocalLink($out);
701 $message = $this->callHook(
"onAfterSaveTransaction");
705 if ($policy ==
"global") {
706 if ($out->status == self::successTransaction) {
707 $this->domain->commitPoint($beforeSavePoint);
709 $out->status = self::abortTransaction;
710 $this->domain->rollbackPoint($beforeSavePoint);
713 $out->message = $message;
716 $out->status = self::abortTransaction;
717 $out->statusMessage = $err;
721 $out->error = _(
"endTransaction:no transaction identificator");
722 $out->status = self::abortTransaction;
724 $this->domain->addLog(__METHOD__, $out);
725 $ufolder = $this->domain->getUserFolder();
726 $out->manageWaitingUrl = getParam(
"CORE_EXTERNURL") .
'?app=OFFLINE&action=OFF_ORGANIZER&domain=0&dirid=' . $ufolder->id .
'&transaction=' . $config->transaction;
730 private function saveWaitings(&$waitings)
733 foreach ($waitings as $k => $waitDoc) {
734 if ($waitDoc->status == $waitDoc::invalid) {
735 $out[$waitDoc->refererinitid] = array(
736 "statusMessage" => $waitDoc->statusmessage,
737 "statusCode" => $waitDoc->status,
741 $waitPoint =
"docw" . $k;
742 $this->domain->savePoint($waitPoint);
743 $needToRollback =
false;
745 $eExtra = $waitDoc->getExtraData();
746 $saveerr = $this->callHook(
"onBeforeSaveDocument", $waitDoc->getWaitingDocument() , $waitDoc->getRefererDocument() , $eExtra);
749 if ($waitDoc->getRefererDocument()) {
751 $savectxerr =
"getRefererDocument";
754 $savectxerr =
"onBeforeSaveDocument";
756 if ($saveerr ==
"") {
758 $saveerr = $waitDoc->save($saveInfo);
759 $out[$waitDoc->refererinitid] = array(
760 "statusMessage" => $waitDoc->statusmessage,
761 "saveInfo" => $saveInfo,
762 "statusCode" => $waitDoc->status,
763 "localId" => $waitDoc->localid,
764 "isValid" => $waitDoc->isValid()
766 if ($saveerr ==
'') {
767 if ($waitDoc->localid) {
768 $this->domain->insertUserDocument($waitDoc->refererinitid, $this->domain->getSystemUserId() ,
true);
769 $morelinks = $this->resolveLocalLinks($waitDoc->localid, $waitDoc->refererinitid);
770 foreach ($morelinks as $mid => $link) {
771 if (!$out[$mid]) $out[$mid] = $link;
774 $message = $this->callHook(
"onAfterSaveDocument", $waitDoc->getRefererDocument() , $eExtra);
775 $out[$waitDoc->refererinitid][
"saveInfo"]->onAfterSaveDocument = $message;
776 if ($eExtra->changeState) {
777 $refererDocument = $waitDoc->getRefererDocument();
778 $beforeChangeStateReferId = $refererDocument->getProperty(
"id");
779 $message = $this->afterSaveChangeState($refererDocument, $eExtra->changeState);
780 if ($message && $beforeChangeStateReferId === $refererDocument->getProperty(
"id")) {
781 $needToRollback =
true;
783 $out[$waitDoc->refererinitid][
"saveInfo"]->onAfterSaveChangeState = $message;
786 $needToRollback =
true;
789 $needToRollback =
true;
791 if (!$needToRollback) {
792 $waitDoc->getRefererDocument()->addComment(
"synchronised");
793 $this->domain->commitPoint($waitPoint);
796 "statusMessage" => $saveerr,
797 "statusContext" => $savectxerr,
798 "statusCode" => self::documentNotRecorded,
801 if (is_array($out[$waitDoc->refererinitid])) {
802 $out[$waitDoc->refererinitid] = array_merge($out[$waitDoc->refererinitid], $failOut);
804 $out[$waitDoc->refererinitid] = $failOut;
806 $this->domain->rollbackPoint($waitPoint);
808 $waitDoc->status = $out[$waitDoc->refererinitid][
"statusCode"];
809 $waitDoc->statusmessage = $out[$waitDoc->refererinitid][
"statusMessage"];
810 $waitDoc->modify(
true, array(
"status",
"statusmessage"));
811 $waitDoc->getRefererDocument()->addComment(sprintf(_(
"synchro: %s") , $waitDoc->statusmessage) , HISTO_ERROR);
819 private function resolveLocalLinks($localId, $serverId)
821 $numLocalId = $this->numerizeId($localId);
822 $waitings = DocWaitManager::getWaitingDocsByDomain($this->domain->id);
824 foreach ($waitings as $k => $waitDoc) {
825 if ($waitDoc->status == $waitDoc::upToDate) {
827 $doc = $waitDoc->getRefererDocument();
829 $oas = $doc->getNormalAttributes();
831 foreach ($oas as $aid => $oa) {
832 if ($oa->type ==
"docid") {
833 $value = $doc->getValue($aid);
835 $nvalue = str_replace($numLocalId, $serverId, $value);
836 if ($nvalue != $value) {
837 $doc->setValue($aid, $nvalue);
846 $out[$waitDoc->refererinitid] = array(
847 "statusMessage" => $waitDoc->statusmessage,
848 "statusCode" => $waitDoc->status,
859 private function afterSaveChangeState(Doc & $doc, $newState)
862 $err = $doc->setState($newState, sprintf(_(
"synchronize change state to %s"), $newState));
863 if ($doc->canEdit(
false) ===
'' && $doc->isInDomain()) {
864 $err .= $doc->lockToDomain($this->domain->getProperty(
"id"), DOC::getSystemUserId());
getUserDocuments($config)
__construct($id, $title, $status, $errorMessage, $statusErrorMessage)
__construct(Dir &$domain=null, DomainApi &$domainApi=null)
verifyPrivilege(Doc &$doc)
static isUpToDate(Doc &$doc, array &$stillRecorded)
getSharedDocumentsAcknowledgement($config)
removeUserDocument($config)
getSharedDocuments($config)
const documentNotRecorded
getUserDocumentsAcknowledgement($config)