Example #1
0
 public function copyAction()
 {
     $success = false;
     $sourceId = intval($this->_getParam("sourceId"));
     $source = Document::getById($sourceId);
     $session = new Zend_Session_Namespace("pimcore_copy");
     $targetId = intval($this->_getParam("targetId"));
     if ($this->_getParam("targetParentId")) {
         $sourceParent = Document::getById($this->_getParam("sourceParentId"));
         // this is because the key can get the prefix "_copy" if the target does already exists
         if ($session->{$this->_getParam("transactionId")}["parentId"]) {
             $targetParent = Document::getById($session->{$this->_getParam("transactionId")}["parentId"]);
         } else {
             $targetParent = Document::getById($this->_getParam("targetParentId"));
         }
         $targetPath = preg_replace("@^" . $sourceParent->getFullPath() . "@", $targetParent . "/", $source->getPath());
         $target = Document::getByPath($targetPath);
     } else {
         $target = Document::getById($targetId);
     }
     if ($target instanceof Document) {
         $target->getPermissionsForUser($this->getUser());
         if ($target->isAllowed("create")) {
             if ($source != null) {
                 if ($this->_getParam("type") == "child") {
                     $newDocument = $this->_documentService->copyAsChild($target, $source);
                     $session->{$this->_getParam("transactionId")}["idMapping"][(int) $source->getId()] = (int) $newDocument->getId();
                     // this is because the key can get the prefix "_copy" if the target does already exists
                     if ($this->_getParam("saveParentId")) {
                         $session->{$this->_getParam("transactionId")}["parentId"] = $newDocument->getId();
                     }
                 } else {
                     if ($this->_getParam("type") == "replace") {
                         $this->_documentService->copyContents($target, $source);
                     }
                 }
                 $success = true;
             } else {
                 Logger::error("prevended copy/paste because document with same path+key already exists in this location");
             }
         } else {
             Logger::error("could not execute copy/paste because of missing permissions on target [ " . $targetId . " ]");
             $this->_helper->json(array("success" => false, "message" => "missing_permission"));
         }
     }
     $this->_helper->json(array("success" => $success));
 }
Example #2
0
 /**
  * @param int $id
  * @return Webservice_Data_Document_Snippet_Out
  */
 public function getDocumentSnippetById($id)
 {
     try {
         $snippet = Document::getById($id);
         if ($snippet instanceof Document_Snippet) {
             // load all data (eg. href, snippet, ... which are lazy loaded)
             Document_Service::loadAllDocumentFields($snippet);
             $className = Webservice_Data_Mapper::findWebserviceClass($snippet, "out");
             $apiSnippet = Webservice_Data_Mapper::map($snippet, $className, "out");
             return $apiSnippet;
         }
         throw new Exception("Document Snippet with given ID (" . $id . ") does not exist.");
     } catch (Exception $e) {
         Logger::error($e);
         throw $e;
     }
 }
Example #3
0
 public function correctPath()
 {
     // set path
     if ($this->getId() != 1) {
         // not for the root node
         $parent = Document::getById($this->getParentId());
         if ($parent) {
             $this->setPath(str_replace("//", "/", $parent->getFullPath() . "/"));
         } else {
             // parent document doesn't exist anymore, so delete this document
             //$this->delete();
             // parent document doesn't exist anymore, set the parent to to root
             $this->setParentId(1);
             $this->setPath("/");
         }
     }
     if (Document_Service::pathExists($this->getFullPath())) {
         $duplicate = Document::getByPath($this->getFullPath());
         if ($duplicate instanceof Document and $duplicate->getId() != $this->getId()) {
             throw new Exception("Duplicate full path [ " . $this->getFullPath() . " ] - cannot create document");
         }
     }
 }
Example #4
0
 /**
  * Helper to simply replace the placeholders with there value
  *
  * @param string | Document $mixed
  * @param array $params
  * @param null | Document $document
  * @return string
  */
 public function replacePlaceholders($mixed, $params = array(), $document = null)
 {
     if (is_string($mixed)) {
         $contentString = $mixed;
     } elseif ($mixed instanceof Document) {
         $contentString = Document_Service::render($mixed, $params, true);
     }
     if ($document instanceof Document === false) {
         $document = null;
     }
     //detects the placeholders
     $placeholderStack = $this->detectPlaceholders($contentString, $params, $document);
     //replaces the placeholders if any were found
     if (!empty($placeholderStack)) {
         $replacedString = $this->replacePlaceholdersFromStack($placeholderStack);
         return $replacedString;
     } else {
         return $contentString;
     }
 }
Example #5
0
 /**
  * @static
  * @param $type
  * @param $path
  * @return bool
  */
 public static function pathExists($type, $path)
 {
     if ($type == "asset") {
         return Asset_Service::pathExists($path);
     } else {
         if ($type == "document") {
             return Document_Service::pathExists($path);
         } else {
             if ($type == "object") {
                 return Object_Service::pathExists($path);
             }
         }
     }
 }
 /**
  * @return void
  */
 public function findAction()
 {
     $user = $this->getUser();
     $query = $this->_getParam("query");
     if ($query == "*") {
         $query = "";
     }
     $query = str_replace("%", "*", $query);
     $types = explode(",", $this->_getParam("type"));
     $subtypes = explode(",", $this->_getParam("subtype"));
     $classnames = explode(",", $this->_getParam("class"));
     $offset = intval($this->_getParam("start"));
     $limit = intval($this->_getParam("limit"));
     $offset = $offset ? $offset : 0;
     $limit = $limit ? $limit : 50;
     $searcherList = new Search_Backend_Data_List();
     $conditionParts = array();
     $db = Pimcore_Resource::get();
     //exclude forbidden assets
     if (in_array("asset", $types)) {
         if (!$user->isAllowed("assets")) {
             $forbiddenConditions[] = " `type` != 'asset' ";
         } else {
             $forbiddenAssetPaths = Element_Service::findForbiddenPaths("asset", $user);
             if (count($forbiddenAssetPaths) > 0) {
                 for ($i = 0; $i < count($forbiddenAssetPaths); $i++) {
                     $forbiddenAssetPaths[$i] = " (maintype = 'asset' AND fullpath not like " . $db->quote($forbiddenAssetPaths[$i] . "%") . ")";
                 }
                 $forbiddenConditions[] = implode(" AND ", $forbiddenAssetPaths);
             }
         }
     }
     //exclude forbidden documents
     if (in_array("document", $types)) {
         if (!$user->isAllowed("documents")) {
             $forbiddenConditions[] = " `type` != 'document' ";
         } else {
             $forbiddenDocumentPaths = Element_Service::findForbiddenPaths("document", $user);
             if (count($forbiddenDocumentPaths) > 0) {
                 for ($i = 0; $i < count($forbiddenDocumentPaths); $i++) {
                     $forbiddenDocumentPaths[$i] = " (maintype = 'document' AND fullpath not like " . $db->quote($forbiddenDocumentPaths[$i] . "%") . ")";
                 }
                 $forbiddenConditions[] = implode(" AND ", $forbiddenDocumentPaths);
             }
         }
     }
     //exclude forbidden objects
     if (in_array("object", $types)) {
         if (!$user->isAllowed("objects")) {
             $forbiddenConditions[] = " `type` != 'object' ";
         } else {
             $forbiddenObjectPaths = Element_Service::findForbiddenPaths("object", $user);
             if (count($forbiddenObjectPaths) > 0) {
                 for ($i = 0; $i < count($forbiddenObjectPaths); $i++) {
                     $forbiddenObjectPaths[$i] = " (maintype = 'object' AND fullpath not like " . $db->quote($forbiddenObjectPaths[$i] . "%") . ")";
                 }
                 $forbiddenConditions[] = implode(" AND ", $forbiddenObjectPaths);
             }
         }
     }
     if ($forbiddenConditions) {
         $conditionParts[] = "(" . implode(" AND ", $forbiddenConditions) . ")";
     }
     if (!empty($query)) {
         $queryCondition = "( MATCH (`data`,`properties`) AGAINST (" . $db->quote($query) . " IN BOOLEAN MODE) )";
         // the following should be done with an exact-search now "ID", because the Element-ID is now in the fulltext index
         // if the query is numeric the user might want to search by id
         //if(is_numeric($query)) {
         //$queryCondition = "(" . $queryCondition . " OR id = " . $db->quote($query) ." )";
         //}
         $conditionParts[] = $queryCondition;
     }
     //For objects - handling of bricks
     $fields = array();
     $bricks = array();
     if ($this->_getParam("fields")) {
         $fields = $this->_getParam("fields");
         foreach ($fields as $f) {
             $parts = explode("~", $f);
             if (count($parts) > 1) {
                 $bricks[$parts[0]] = $parts[0];
             }
         }
     }
     // filtering for objects
     if ($this->_getParam("filter")) {
         $class = Object_Class::getByName($this->_getParam("class"));
         $conditionFilters = Object_Service::getFilterCondition($this->_getParam("filter"), $class);
         $join = "";
         foreach ($bricks as $ob) {
             $join .= " LEFT JOIN object_brick_query_" . $ob . "_" . $class->getId();
             $join .= " `" . $ob . "`";
             $join .= " ON `" . $ob . "`.o_id = `object_" . $class->getId() . "`.o_id";
         }
         $conditionParts[] = "( id IN (SELECT `object_" . $class->getId() . "`.o_id FROM object_" . $class->getId() . $join . " WHERE 1=1 " . $conditionFilters . ") )";
     }
     if (is_array($types) and !empty($types[0])) {
         foreach ($types as $type) {
             $conditionTypeParts[] = $db->quote($type);
         }
         $conditionParts[] = "( maintype IN (" . implode(",", $conditionTypeParts) . ") )";
     }
     if (is_array($subtypes) and !empty($subtypes[0])) {
         foreach ($subtypes as $subtype) {
             $conditionSubtypeParts[] = $db->quote($subtype);
         }
         $conditionParts[] = "( type IN (" . implode(",", $conditionSubtypeParts) . ") )";
     }
     if (is_array($classnames) and !empty($classnames[0])) {
         if (in_array("folder", $subtypes)) {
             $classnames[] = "folder";
         }
         foreach ($classnames as $classname) {
             $conditionClassnameParts[] = $db->quote($classname);
         }
         $conditionParts[] = "( subtype IN (" . implode(",", $conditionClassnameParts) . ") )";
     }
     if (count($conditionParts) > 0) {
         $condition = implode(" AND ", $conditionParts);
         //echo $condition; die();
         $searcherList->setCondition($condition);
     }
     $searcherList->setOffset($offset);
     $searcherList->setLimit($limit);
     // do not sort per default, it is VERY SLOW
     //$searcherList->setOrder("desc");
     //$searcherList->setOrderKey("modificationdate");
     if ($this->_getParam("sort")) {
         $searcherList->setOrderKey($this->_getParam("sort"));
     }
     if ($this->_getParam("dir")) {
         $searcherList->setOrder($this->_getParam("dir"));
     }
     $hits = $searcherList->load();
     $elements = array();
     foreach ($hits as $hit) {
         $element = Element_Service::getElementById($hit->getId()->getType(), $hit->getId()->getId());
         if ($element->isAllowed("list")) {
             if ($element instanceof Object_Abstract) {
                 $data = Object_Service::gridObjectData($element, $fields);
             } else {
                 if ($element instanceof Document) {
                     $data = Document_Service::gridDocumentData($element);
                 } else {
                     if ($element instanceof Asset) {
                         $data = Asset_Service::gridAssetData($element);
                     }
                 }
             }
             $elements[] = $data;
         } else {
             //TODO: any message that view is blocked?
             //$data = Element_Service::gridElementData($element);
         }
     }
     // only get the real total-count when the limit parameter is given otherwise use the default limit
     if ($this->_getParam("limit")) {
         $totalMatches = $searcherList->getTotalCount();
     } else {
         $totalMatches = count($elements);
     }
     $this->_helper->json(array("data" => $elements, "success" => true, "total" => $totalMatches));
     $this->removeViewRenderer();
 }
Example #7
0
 public function listReservationsByGuest()
 {
     $optionalParams = array('guestid' => $this->id, 'calendar' => '15-10-2015');
     $useLayout = false;
     return Document_Service::render(Document::getById(85), $optionalParams, $useLayout);
 }
Example #8
0
 public function testCopyAndDeleteDocument()
 {
     $documentList = new Document_List();
     $documentList->setCondition("`key` like '%_data%' and `type` = 'page'");
     $documents = $documentList->load();
     $parent = $documents[0];
     $this->assertTrue($parent instanceof Document_Page);
     //remove childs if there are some
     if ($parent->hasChilds()) {
         foreach ($parent->getChilds() as $child) {
             $child->delete();
         }
     }
     $this->assertFalse($parent->hasChilds());
     $service = new Document_Service(User::getById(1));
     //copy as child
     $service->copyAsChild($parent, $parent);
     $this->assertTrue($parent->hasChilds());
     $this->assertTrue(count($parent->getChilds()) == 1);
     //copy as child no. 2
     $service->copyAsChild($parent, $parent);
     $this->assertTrue($parent->hasChilds());
     $this->assertTrue(count($parent->getChilds()) == 2);
     $childs = $parent->getChilds();
     $this->assertTrue(Test_Tool::documentsAreEqual($parent, $childs[0], true));
     $this->assertTrue(Test_Tool::documentsAreEqual($parent, $childs[1], true));
     //copy recursivley
     $rootNode = Document::getById(1);
     $copy = $service->copyRecursive($rootNode, $parent);
     $this->assertTrue($copy->hasChilds());
     $this->assertTrue(count($copy->getChilds()) == 2);
     $this->assertTrue(Test_Tool::documentsAreEqual($parent, $copy, true));
     //create empty document
     $emptyDoc = Document_Page::create(1, array("userOwner" => 1, "key" => uniqid() . rand(10, 99)));
     $this->assertFalse(Test_Tool::documentsAreEqual($emptyDoc, $copy, true));
     //copy contents
     $emptyDoc = $service->copyContents($emptyDoc, $copy);
     $this->assertTrue(Test_Tool::documentsAreEqual($emptyDoc, $copy, true));
     //todo copy contents must fail if types differ
     //delete recusively
     $shouldBeDeleted[] = $copy->getId();
     $childs = $copy->getChilds();
     foreach ($childs as $child) {
         $shouldBeDeleted[] = $child->getId();
     }
     $copy->delete();
     foreach ($shouldBeDeleted as $id) {
         $o = Document::getById($id);
         $this->assertFalse($o instanceof Document);
     }
 }
Example #9
0
    public function postDispatch(Zend_Controller_Request_Abstract $request)
    {
        // add scripts to editmode
        $editmodeLibraries = array("/pimcore/static/js/pimcore/namespace.js", "/pimcore/static/js/lib/prototype-light.js", "/pimcore/static/js/lib/jquery-1.4.2.min.js", "/pimcore/static/js/lib/ext/adapter/jquery/ext-jquery-adapter-debug.js", "/pimcore/static/js/lib/ext/ext-all-debug.js", "/pimcore/static/js/lib/ext-plugins/ux/Spinner.js", "/pimcore/static/js/lib/ext-plugins/ux/SpinnerField.js", "/pimcore/static/js/lib/ext-plugins/ux/MultiSelect.js", "/pimcore/static/js/lib/ext-plugins/ux/Portal.js", "/pimcore/static/js/lib/ext-plugins/ux/PortalColumn.js", "/pimcore/static/js/lib/ext-plugins/ux/Portlet.js", "/pimcore/static/js/lib/ext-plugins/GridRowOrder/roworder.js", "/pimcore/static/js/lib/ckeditor/ckeditor.js", "/pimcore/static/js/pimcore/libfixes.js");
        $editmodeScripts = array("/pimcore/static/js/pimcore/functions.js", "/pimcore/static/js/pimcore/document/edit/helper.js", "/pimcore/static/js/pimcore/document/edit/dnd.js", "/pimcore/static/js/pimcore/document/tag.js", "/pimcore/static/js/pimcore/document/tags/block.js", "/pimcore/static/js/pimcore/document/tags/date.js", "/pimcore/static/js/pimcore/document/tags/href.js", "/pimcore/static/js/pimcore/document/tags/multihref.js", "/pimcore/static/js/pimcore/document/tags/checkbox.js", "/pimcore/static/js/pimcore/document/tags/image.js", "/pimcore/static/js/pimcore/document/tags/input.js", "/pimcore/static/js/pimcore/document/tags/link.js", "/pimcore/static/js/pimcore/document/tags/select.js", "/pimcore/static/js/pimcore/document/tags/snippet.js", "/pimcore/static/js/pimcore/document/tags/textarea.js", "/pimcore/static/js/pimcore/document/tags/numeric.js", "/pimcore/static/js/pimcore/document/tags/wysiwyg.js", "/pimcore/static/js/pimcore/document/tags/renderlet.js", "/pimcore/static/js/pimcore/document/tags/table.js", "/pimcore/static/js/pimcore/document/tags/video.js", "/pimcore/static/js/pimcore/document/tags/multiselect.js", "/pimcore/static/js/pimcore/document/tags/areablock.js", "/pimcore/static/js/pimcore/document/tags/area.js", "/pimcore/static/js/pimcore/document/edit/helper.js");
        $conf = Pimcore_Config::getSystemConfig();
        $themeUrl = "/pimcore/static/js/lib/ext/resources/css/xtheme-blue.css";
        if ($conf->general->theme) {
            $themeUrl = $conf->general->theme;
        }
        $editmodeStylesheets = array("/pimcore/static/js/lib/ext/resources/css/ext-all.css", $themeUrl, "/pimcore/static/css/icons.css", "/pimcore/static/css/editmode.css", "/pimcore/static/js/lib/ext-plugins/ux/css/Spinner.css", "/pimcore/static/js/lib/ext-plugins/ux/css/MultiSelect.css", "/pimcore/static/js/lib/ext-plugins/ux/css/Portal.css");
        //add plugin editmode JS and CSS
        try {
            $pluginConfigs = Pimcore_ExtensionManager::getPluginConfigs();
            $jsPaths = array();
            $cssPaths = array();
            if (!empty($pluginConfigs)) {
                //registering plugins
                foreach ($pluginConfigs as $p) {
                    if (is_array($p['plugin']['pluginDocumentEditmodeJsPaths']['path'])) {
                        $jsPaths = $p['plugin']['pluginDocumentEditmodeJsPaths']['path'];
                    } else {
                        if ($p['plugin']['pluginDocumentEditmodeJsPaths']['path'] != null) {
                            $jsPaths[0] = $p['plugin']['pluginDocumentEditmodeJsPaths']['path'];
                        }
                    }
                    //manipulate path for frontend
                    if (is_array($jsPaths) and count($jsPaths) > 0) {
                        for ($i = 0; $i < count($jsPaths); $i++) {
                            if (is_file(PIMCORE_PLUGINS_PATH . $jsPaths[$i])) {
                                $jsPaths[$i] = "/plugins" . $jsPaths[$i];
                            }
                        }
                    }
                    if (is_array($p['plugin']['pluginDocumentEditmodeCssPaths']['path'])) {
                        $cssPaths = $p['plugin']['pluginDocumentEditmodeCssPaths']['path'];
                    } else {
                        if ($p['plugin']['pluginDocumentEditmodeCssPaths']['path'] != null) {
                            $cssPaths[0] = $p['plugin']['pluginDocumentEditmodeCssPaths']['path'];
                        }
                    }
                    //manipulate path for frontend
                    if (is_array($cssPaths) and count($cssPaths) > 0) {
                        for ($i = 0; $i < count($cssPaths); $i++) {
                            if (is_file(PIMCORE_PLUGINS_PATH . $cssPaths[$i])) {
                                $cssPaths[$i] = "/plugins" . $cssPaths[$i];
                            }
                        }
                    }
                }
            }
            $editmodeScripts = array_merge($editmodeScripts, $jsPaths);
            $editmodeStylesheets = array_merge($editmodeStylesheets, $cssPaths);
        } catch (Exception $e) {
            Logger::alert("there is a problem with the plugin configuration");
            Logger::alert($e);
        }
        $editmodeHeadHtml = "\n\n\n<!-- pimcore editmode -->\n";
        // include stylesheets
        foreach ($editmodeStylesheets as $sheet) {
            $editmodeHeadHtml .= '<link rel="stylesheet" type="text/css" href="' . $sheet . '?_dc=' . Pimcore_Version::$revision . '" />';
            $editmodeHeadHtml .= "\n";
        }
        // include script libraries
        foreach ($editmodeLibraries as $script) {
            $editmodeHeadHtml .= '<script type="text/javascript" src="' . $script . '?_dc=' . Pimcore_Version::$revision . '"></script>';
            $editmodeHeadHtml .= "\n";
        }
        // combine the pimcore scripts in non-devmode
        if ($conf->general->devmode) {
            foreach ($editmodeScripts as $script) {
                $editmodeHeadHtml .= '<script type="text/javascript" src="' . $script . '?_dc=' . Pimcore_Version::$revision . '"></script>';
                $editmodeHeadHtml .= "\n";
            }
        } else {
            $scriptContents = "";
            foreach ($editmodeScripts as $scriptUrl) {
                $scriptContents .= file_get_contents(PIMCORE_DOCUMENT_ROOT . $scriptUrl) . "\n\n\n";
            }
            $editmodeHeadHtml .= '<script type="text/javascript" src="' . Pimcore_Tool_Admin::getMinimizedScriptPath($scriptContents) . '?_dc=' . Pimcore_Version::$revision . '"></script>' . "\n";
        }
        $ns = new Zend_Session_Namespace("pimcore_admin");
        $user = User::getById($ns->user->getId());
        $lang = $user->getLanguage();
        $editmodeHeadHtml .= '<script type="text/javascript" src="/admin/misc/json-translations-system/language/' . $lang . '/?_dc=' . Pimcore_Version::$revision . '"></script>' . "\n";
        $editmodeHeadHtml .= '<script type="text/javascript" src="/admin/misc/json-translations-admin/language/' . $lang . '/?_dc=' . Pimcore_Version::$revision . '"></script>' . "\n";
        $editmodeHeadHtml .= "\n\n";
        // set var for editable configurations which is filled by Document_Tag::admin()
        $editmodeHeadHtml .= '<script type="text/javascript">
            var editableConfigurations = new Array();
            var pimcore_document_id = ' . $request->getParam("document")->getId() . ';
        </script>';
        $editmodeHeadHtml .= "\n\n<!-- /pimcore editmode -->\n\n\n";
        // add html headers for snippets in editmode, so there is no problem with javascript
        $body = $this->getResponse()->getBody();
        if ($this->controller->editmode && strpos($body, "</body>") === false && !$request->getParam("blockAutoHtml")) {
            $body = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
			<html xmlns="http://www.w3.org/1999/xhtml">
			<head></head><body>' . $body . "</body></html>";
            $this->getResponse()->setBody($body);
        }
        // add scripts in html header for pages in editmode
        if ($this->controller->editmode && Document_Service::isValidType($this->controller->document->getType())) {
            //ckogler
            include_once "simple_html_dom.php";
            $body = $this->getResponse()->getBody();
            $html = str_get_html($body);
            if ($html) {
                if ($head = $html->find("head", 0)) {
                    $head->innertext = $head->innertext . "\n\n" . $editmodeHeadHtml;
                    $bodyElement = $html->find("body", 0);
                    $bodyElement->onunload = "pimcoreOnUnload();";
                    $bodyElement->innertext = $bodyElement->innertext . "\n\n" . '<script type="text/javascript" src="/pimcore/static/js/pimcore/document/edit/startup.js?_dc=' . Pimcore_Version::$revision . '"></script>' . "\n\n";
                    $body = $html->save();
                    $this->getResponse()->setBody($body);
                }
            }
        }
    }
Example #10
0
 /**
  * @static
  * @param Element_Interface $element
  * @return Element_Interface
  */
 public static function loadAllFields(Element_Interface $element)
 {
     if ($element instanceof Document) {
         Document_Service::loadAllDocumentFields($element);
     } else {
         if ($element instanceof Object_Concrete) {
             Object_Service::loadAllObjectFields($element);
         }
     }
     return $element;
 }
Example #11
0
 protected function documentTest($subtype)
 {
     $client = $this->getSoapClient();
     //get an document list with 3 elements
     $condition = "`type`= '" . $subtype . "'";
     $generalCondition = $this->getListCondition();
     if (!empty($generalCondition)) {
         if (!empty($condition)) {
             $condition .= " AND " . $generalCondition;
         } else {
             $condition = $generalCondition;
         }
     }
     $order = "";
     $orderKey = "";
     $offset = 0;
     $limit = 3;
     $groupBy = "";
     $wsDocument = $client->getDocumentList($condition, $order, $orderKey, $offset, $limit, $groupBy);
     $this->assertTrue(is_array($wsDocument) and $wsDocument[0] instanceof Webservice_Data_Document_List_Item);
     //take the first element and fetch
     $documentId = $wsDocument[0]->id;
     $this->assertTrue(is_numeric($documentId));
     $wsMethod = "getDocument" . ucfirst($subtype) . "ById";
     $wsDocument = $client->{$wsMethod}($documentId);
     $wsDataClassIn = "Webservice_Data_Document_" . ucfirst($subtype) . "_In";
     $wsDataClassOut = "Webservice_Data_Document_" . ucfirst($subtype) . "_Out";
     $localClass = "Document_" . ucfirst($subtype);
     $this->assertTrue($wsDocument instanceof $wsDataClassOut);
     $document = new $localClass();
     $wsDocument->reverseMap($document);
     //some checks to see if we got a valid document
     $this->assertTrue($document->getCreationDate() > 0);
     $this->assertTrue(strlen($document->getPath()) > 0);
     //copy the document retrieved from ws
     $new = clone $document;
     $new->id = null;
     $new->setKey($document->getKey() . "_phpUnitTestCopy");
     $new->setResource(null);
     //send new document back via ws
     $apiPage = Webservice_Data_Mapper::map($new, $wsDataClassIn, "in");
     $wsMethod = "createDocument" . ucfirst($subtype);
     $id = $client->{$wsMethod}($apiPage);
     $this->assertTrue($id > 0);
     $wsMethod = "getDocument" . ucfirst($subtype) . "ById";
     $wsDocument = $client->{$wsMethod}($id);
     $this->assertTrue($wsDocument instanceof $wsDataClassOut);
     $refetchDocument = new $localClass();
     $wsDocument->reverseMap($refetchDocument);
     $this->assertTrue($refetchDocument->getId() > 1);
     $localDocument = $localClass::getById($documentId);
     Document_Service::loadAllDocumentFields($localDocument);
     //do that now, later id is null
     $localDocument->getProperties();
     //remove childs, this can not be set through WS
     $localDocument->childs = null;
     $this->assertTrue(Test_Tool::documentsAreEqual($localDocument, $refetchDocument, true));
     //update document
     if ($document instanceof Document_PageSnippet) {
         $refetchDocument->setPublished(!$refetchDocument->getPublished());
     }
     $refetchDocument->setProperty("updateTest", "text", "a update test");
     $apiPage = Webservice_Data_Mapper::map($refetchDocument, $wsDataClassIn, "in");
     $wsMethod = "updateDocument" . ucfirst($subtype);
     $success = $client->{$wsMethod}($apiPage);
     $this->assertTrue($success);
     $documentId = $refetchDocument->getId();
     $localDocument = $localClass::getById($documentId);
     $localDocument->getProperties();
     $localDocument->childs = null;
     $this->assertTrue(Test_Tool::documentsAreEqual($localDocument, $refetchDocument, true));
     //delete our test copy
     $success = $client->deleteDocument($refetchDocument->getId());
     $this->assertTrue($success);
 }