/**
  * Fetches the site with the given name and exports it into XML.
  *
  * @param array<\TYPO3\TYPO3\Domain\Model\Site> $sites
  * @return void
  */
 public function export(array $sites)
 {
     $this->nodeRepository->getContext()->setInvisibleContentShown(TRUE);
     $this->nodeRepository->getContext()->setInaccessibleContentShown(TRUE);
     $xmlWriter = new \XMLWriter();
     $xmlWriter->openUri('php://output');
     $xmlWriter->startDocument('1.0', 'UTF-8');
     $xmlWriter->startElement('root');
     foreach ($sites as $site) {
         $xmlWriter->startElement('site');
         // site attributes
         $xmlWriter->writeAttribute('nodeName', $site->getNodeName());
         // site properties
         $xmlWriter->startElement('properties');
         $xmlWriter->writeElement('name', $site->getName());
         $xmlWriter->writeElement('state', $site->getState());
         $xmlWriter->writeElement('siteResourcesPackageKey', $site->getSiteResourcesPackageKey());
         $xmlWriter->endElement();
         // on to the nodes...
         $node = $this->nodeRepository->getContext()->getNode('/Sites/' . $site->getNodeName());
         foreach ($node->getChildNodes() as $childNode) {
             $this->exportNode($childNode, $xmlWriter);
         }
         $xmlWriter->endElement();
     }
     $xmlWriter->endElement();
     $xmlWriter->endDocument();
     $xmlWriter->flush();
 }
 /**
  * Search all properties for given $term
  * @param string $term
  * @param array $searchContentTypes
  * @return \TYPO3\FLOW3\Persistence\QueryResultInterface
  */
 public function findByProperties($term, array $searchContentTypes)
 {
     // TODO: Implement a better search when FLOW3 offer the possibility
     $query = $this->nodeRepository->createQuery();
     $constraints = array($query->like('properties', '%' . $term . '%'), $query->in('contentType', $searchContentTypes));
     return $query->matching($query->logicalAnd($constraints))->execute();
 }
 /**
  * Is it possile to render $node with $typoScriptPath?
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $node
  * @param string $typoScriptPath
  * @return boolean TRUE if $node can be rendered at $typoScriptPath
  */
 public function canRenderWithNodeAndPath(\TYPO3\TYPO3CR\Domain\Model\NodeInterface $node, $typoScriptPath)
 {
     $currentSiteNode = $this->nodeRepository->getContext()->getCurrentSiteNode();
     // TODO: find closest folder node from this node...
     $closestFolderNode = $node;
     $typoScriptConfiguration = $this->typoScriptService->getMergedTypoScriptObjectTree($currentSiteNode, $closestFolderNode);
     $typoScriptRuntime = new \TYPO3\TypoScript\Core\Runtime($typoScriptConfiguration, $this->controllerContext);
     return $typoScriptRuntime->canRender($typoScriptPath);
 }
 /**
  * Returns the specified node
  *
  * @param string $term
  * @param integer $requestIndex
  * @return void
  * @ExtDirect
  * @todo Improve this WIP search implementation
  */
 public function searchAction($term, $requestIndex)
 {
     $contentContext = new \TYPO3\TYPO3\Domain\Service\ContentContext($this->securityContext->getParty()->getPreferences()->get('context.workspace'));
     $this->nodeRepository->setContext($contentContext);
     $searchContentGroups = array();
     $searchContentTypes = array();
     foreach (array('TYPO3.Phoenix.ContentTypes:Page', 'TYPO3.Phoenix.ContentTypes:ContentObject') as $contentType) {
         $searchContentGroups[$contentType] = $this->contentTypeManager->getContentType($contentType)->getConfiguration();
         array_push($searchContentTypes, $contentType);
         $subContentTypes = $this->contentTypeManager->getSubContentTypes($contentType);
         if (count($subContentTypes) > 0) {
             $searchContentGroups[$contentType]['subContentTypes'] = $subContentTypes;
             $searchContentTypes = array_merge($searchContentTypes, array_keys($subContentTypes));
         }
     }
     $staticWebBaseUri = $this->resourcePublisher->getStaticResourcesWebBaseUri() . 'Packages/TYPO3.TYPO3/';
     $groups = array();
     foreach ($this->nodeSearchService->findByProperties($term, $searchContentTypes) as $result) {
         $contentType = $result->getContentType();
         if (array_key_exists($contentType->getName(), $searchContentGroups)) {
             $type = $contentType->getName();
         } else {
             foreach ($searchContentGroups as $searchContentGroup => $searchContentGroupConfiguration) {
                 if (isset($searchContentGroupConfiguration['subContentTypes']) && array_key_exists($contentType->getName(), $searchContentGroupConfiguration['subContentTypes'])) {
                     $type = $searchContentGroup;
                     break;
                 }
             }
         }
         if (!array_key_exists($type, $groups)) {
             $groups[$type] = array('type' => $contentType->getName(), 'label' => $searchContentGroups[$type]['search'], 'items' => array());
         }
         foreach ($contentType->getProperties() as $property => $configuration) {
             if ($property[0] !== '_') {
                 $labelProperty = $property;
                 break;
             }
         }
         $this->uriBuilder->reset();
         if ($result->getContentType()->isOfType('TYPO3.Phoenix.ContentTypes:Page')) {
             $pageNode = $result;
         } else {
             $pageNode = $this->findNextParentFolderNode($result);
             $this->uriBuilder->setSection('c' . $result->getIdentifier());
         }
         $searchResult = array('type' => $contentType->getName(), 'label' => substr(trim(strip_tags($result->getProperty($labelProperty))), 0, 50), 'action' => $this->uriBuilder->uriFor('show', array('node' => $pageNode), 'Frontend\\Node', 'TYPO3.TYPO3'), 'path' => $result->getPath());
         $contentTypeConfiguration = $contentType->getConfiguration();
         if (isset($contentTypeConfiguration['darkIcon'])) {
             $searchResult['icon'] = $staticWebBaseUri . $contentTypeConfiguration['darkIcon'];
         }
         array_push($groups[$type]['items'], $searchResult);
     }
     $data = array('requestIndex' => $requestIndex, 'actions' => array(array('label' => 'Clear all cache', 'command' => 'clear:cache:all'), array('label' => 'Clear page cache', 'command' => 'clear:cache:pages')), 'results' => array_values($groups));
     $this->view->assign('value', array('data' => $data, 'success' => TRUE));
 }
 /**
  * Render the Uri.
  *
  * @param mixed $node A node object or a node path
  * @param string $format Format to use for the URL, for example "html" or "json"
  * @param boolean $absolute If set, an absolute URI is rendered
  * @return string The rendered URI
  */
 public function render($node = NULL, $format = NULL, $absolute = FALSE)
 {
     $request = $this->controllerContext->getRequest()->getMainRequest();
     $uriBuilder = new \TYPO3\FLOW3\Mvc\Routing\UriBuilder();
     $uriBuilder->setRequest($request);
     if ($node === NULL) {
         $node = $this->nodeRepository->getContext()->getCurrentNode();
     }
     if ($format === NULL) {
         $format = $request->getFormat();
     }
     $uri = $uriBuilder->reset()->setCreateAbsoluteUri($absolute)->setFormat($format)->uriFor('show', array('node' => $node), 'Frontend\\Node', 'TYPO3.TYPO3');
     return $uri;
 }
 /**
  * @param \TYPO3\Form\Core\Model\FinisherContext $finisherContext
  * @return void
  * @throws \TYPO3\Setup\Exception
  */
 public function importSite(\TYPO3\Form\Core\Model\FinisherContext $finisherContext)
 {
     $formValues = $finisherContext->getFormRuntime()->getFormState()->getFormValues();
     if (isset($formValues['prune']) && intval($formValues['prune']) === 1) {
         $this->nodeRepository->removeAll();
         $this->workspaceRepository->removeAll();
         $this->domainRepository->removeAll();
         $this->siteRepository->removeAll();
         $this->persistenceManager->persistAll();
     }
     if (!empty($formValues['packageKey'])) {
         if ($this->packageManager->isPackageAvailable($formValues['packageKey'])) {
             throw new \TYPO3\Setup\Exception(sprintf('The package key "%s" already exists.', $formValues['packageKey']), 1346759486);
         }
         $packageKey = $formValues['packageKey'];
         $siteName = $formValues['packageKey'];
         $this->packageManager->createPackage($packageKey, NULL, Files::getUnixStylePath(Files::concatenatePaths(array(FLOW3_PATH_PACKAGES, 'Sites'))));
         $this->generatorService->generateSitesXml($packageKey, $siteName);
         $this->generatorService->generateSitesTypoScript($packageKey, $siteName);
         $this->generatorService->generateSitesTemplate($packageKey, $siteName);
         $this->packageManager->activatePackage($packageKey);
     } else {
         $packageKey = $formValues['site'];
     }
     if ($packageKey !== '') {
         try {
             $contentContext = new \TYPO3\TYPO3\Domain\Service\ContentContext('live');
             $this->nodeRepository->setContext($contentContext);
             $this->siteImportService->importFromPackage($packageKey);
         } catch (\Exception $exception) {
             $finisherContext->cancel();
             $this->flashMessageContainer->addMessage(new \TYPO3\FLOW3\Error\Error(sprintf('Error: During the import of the "Sites.xml" from the package "%s" an exception occurred: %s', $packageKey, $exception->getMessage())));
         }
     }
 }
 /**
  * Returns the menu items according to the defined settings.
  *
  * @return array
  */
 public function getItems()
 {
     if ($this->items === NULL) {
         $this->items = $this->buildItems($this->nodeRepository->getContext());
     }
     return $this->items;
 }
 /**
  * Checks, whether given value is a Node object and if so, sets $this->value to the respective node context path.
  *
  * In order to render a suitable frontend URI, this function strips off the path to the site node and only keeps
  * the actual node path relative to that site node. In practice this function would set $this->value as follows:
  *
  * absolute node path: /sites/footypo3org/homepage/about
  * $this->value:       homepage/about
  *
  * absolute node path: /sites/footypo3org/homepage/about@user-admin
  * $this->value:       homepage/about@user-admin
  *
  * @param mixed $value Either a Node object or an absolute context node path
  * @return boolean TRUE if value could be resolved successfully, otherwise FALSE.
  */
 protected function resolveValue($value)
 {
     if (!$value instanceof NodeInterface && !is_string($value)) {
         return FALSE;
     }
     if (is_string($value)) {
         preg_match(NodeInterface::MATCH_PATTERN_CONTEXTPATH, $value, $matches);
         if (!isset($matches['NodePath'])) {
             return FALSE;
         }
         $contentContext = $this->nodeRepository->getContext();
         if ($contentContext->getWorkspace(FALSE) === NULL) {
             return FALSE;
         }
         $node = $contentContext->getCurrentSiteNode()->getNode($matches['NodePath']);
     } else {
         $node = $value;
         $contentContext = $this->nodeRepository->getContext();
     }
     if ($node instanceof NodeInterface) {
         while ($node->getContentType()->isOfType('TYPO3.Phoenix.ContentTypes:Shortcut')) {
             $childNodes = $node->getChildNodes('TYPO3.Phoenix.ContentTypes:Page,TYPO3.Phoenix.ContentTypes:Shortcut');
             $node = current($childNodes);
         }
         $nodeContextPath = $node->getContextPath();
         $siteNodePath = $contentContext->getCurrentSiteNode()->getPath();
     } else {
         return FALSE;
     }
     if (substr($nodeContextPath, 0, strlen($siteNodePath)) !== $siteNodePath) {
         return FALSE;
     }
     $this->value = substr($nodeContextPath, strlen($siteNodePath) + 1);
     return TRUE;
 }
 /**
  * @param string $workspaceName
  * @return void
  */
 public function discardWorkspaceAction($workspaceName)
 {
     foreach ($this->workspacesService->getUnpublishedNodes($workspaceName) as $node) {
         if ($node->getPath() !== '/') {
             $this->nodeRepository->remove($node);
         }
     }
     $this->flashMessageContainer->addMessage(new \TYPO3\FLOW3\Error\Message('Changes in workspace "%s" have been discarded', NULL, array($workspaceName)));
     $this->redirect('index');
 }
 /**
  * {@inheritdoc}
  *
  * @param \TYPO3\Eel\FlowQuery\FlowQuery $flowQuery the FlowQuery object
  * @param array $arguments the arguments for this operation
  * @return mixed|null if the operation is final, the return value
  */
 public function evaluate(\TYPO3\Eel\FlowQuery\FlowQuery $flowQuery, array $arguments)
 {
     $output = array();
     $outputNodePaths = array();
     foreach ($flowQuery->getContext() as $contextNode) {
         $siteNode = $this->nodeRepository->getContext()->getCurrentSiteNode();
         while ($contextNode->getParent() !== $siteNode) {
             $contextNode = $contextNode->getParent();
             if (!isset($outputNodePaths[$contextNode->getPath()])) {
                 $output[] = $contextNode;
                 $outputNodePaths[$contextNode->getPath()] = TRUE;
             }
         }
     }
     $flowQuery->setContext($output);
     if (isset($arguments[0]) && !empty($arguments[0])) {
         $flowQuery->pushOperation('filter', $arguments);
     }
 }
 /**
  * Search a page, needed for internal links.
  *
  * @param string $query
  * @return void
  * @ExtDirect
  */
 public function searchPageAction($query)
 {
     $contentContext = new \TYPO3\TYPO3\Domain\Service\ContentContext('live');
     $this->nodeRepository->setContext($contentContext);
     $nodes = $this->nodeSearchService->findByProperties($query, array('TYPO3.Phoenix.ContentTypes:Page'));
     $searchResult = array();
     foreach ($nodes as $uninitializedNode) {
         $node = $contentContext->getNode($uninitializedNode->getPath());
         $searchResult[] = $this->processNodeForEditorPlugins($node);
     }
     $this->view->assign('value', array('searchResult' => $searchResult, 'success' => TRUE));
 }
Beispiel #12
0
 /**
  * Returns the initialized node that is referenced by $relativeContextNodePath
  *
  * @param string $relativeContextNodePath
  * @return \TYPO3\TYPO3CR\Domain\Model\NodeInterface
  * @throws \TYPO3\TYPO3\Routing\Exception\NoWorkspaceException
  * @throws \TYPO3\TYPO3\Routing\Exception\NoSiteException
  * @throws \TYPO3\TYPO3\Routing\Exception\NoSuchNodeException
  * @throws \TYPO3\TYPO3\Routing\Exception\NoSiteNodeException
  * @throws \TYPO3\TYPO3\Routing\Exception\InvalidRequestPathException
  */
 public function getNodeByContextNodePath($relativeContextNodePath)
 {
     if ($relativeContextNodePath !== '') {
         preg_match(NodeInterface::MATCH_PATTERN_CONTEXTPATH, $relativeContextNodePath, $matches);
         if (!isset($matches['NodePath'])) {
             throw new Exception\InvalidRequestPathException('The request path "' . $relativeContextNodePath . '" is not valid', 1346949309);
         }
         $relativeNodePath = $matches['NodePath'];
     } else {
         $relativeNodePath = '';
     }
     if ($this->nodeRepository->getContext() === NULL) {
         $workspaceName = isset($matches['WorkspaceName']) ? $matches['WorkspaceName'] : 'live';
         $contentContext = new ContentContext($workspaceName);
         $contentContext->setInvisibleContentShown(TRUE);
         $this->nodeRepository->setContext($contentContext);
     } else {
         $contentContext = $this->nodeRepository->getContext();
     }
     $workspace = $contentContext->getWorkspace(FALSE);
     if (!$workspace) {
         throw new Exception\NoWorkspaceException('No workspace found for request path "' . $relativeContextNodePath . '"', 1346949318);
     }
     $site = $contentContext->getCurrentSite();
     if (!$site) {
         throw new Exception\NoSiteException('No site found for request path "' . $relativeContextNodePath . '"', 1346949693);
     }
     $siteNode = $contentContext->getCurrentSiteNode();
     if (!$siteNode) {
         throw new Exception\NoSiteNodeException('No site node found for request path "' . $relativeContextNodePath . '"', 1346949728);
     }
     $currentAccessModeFromContext = $contentContext->isInaccessibleContentShown();
     $contentContext->setInaccessibleContentShown(TRUE);
     $node = $relativeNodePath === '' ? $siteNode->getPrimaryChildNode() : $siteNode->getNode($relativeNodePath);
     $contentContext->setInaccessibleContentShown($currentAccessModeFromContext);
     if (!$node instanceof NodeInterface) {
         throw new Exception\NoSuchNodeException('No node found on request path "' . $relativeContextNodePath . '"', 1346949857);
     }
     return $node;
 }
 /**
  * Returns a merged TypoScript object tree in the context of the given nodes
  *
  * The start node and end node mark the starting point and end point of the
  * path to take while searching for TypoScript configuration. The path of the
  * start node must be the base path of the end node's path.
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $startNode Node marking the starting point
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $endNode Node marking the end point
  * @return array The merged object tree as of the given node
  */
 public function getMergedTypoScriptObjectTree(\TYPO3\TYPO3CR\Domain\Model\NodeInterface $startNode, \TYPO3\TYPO3CR\Domain\Model\NodeInterface $endNode)
 {
     $contentContext = $this->nodeRepository->getContext();
     $parentNodes = $contentContext->getNodesOnPath($startNode->getPath(), $endNode->getPath());
     if (!is_array($parentNodes)) {
         return NULL;
     }
     $siteResourcesPackageKey = $contentContext->getCurrentSite()->getSiteResourcesPackageKey();
     $typoScriptsPath = sprintf($this->typoScriptsPathPattern, $siteResourcesPackageKey);
     $mergedTypoScriptCode = $this->readExternalTypoScriptFile('resource://TYPO3.TYPO3/Private/DefaultTypoScript/All.ts2');
     $mergedTypoScriptCode .= $this->readExternalTypoScriptFile($typoScriptsPath . '/Library/Root.ts2');
     $currentTypoScriptPath = $typoScriptsPath . '/Nodes';
     foreach ($parentNodes as $node) {
         $nodeName = $node->getName();
         $mergedTypoScriptCode .= Files::getFileContents($this->getMixedCasedPathAndFilename($currentTypoScriptPath . '/' . $nodeName . '.ts2')) . chr(10);
         $currentTypoScriptPath .= '/' . basename($this->getMixedCasedPathAndFilename($currentTypoScriptPath . '/' . $nodeName));
         $typoScriptNodes = $node->getChildNodes('TYPO3.TYPO3:TypoScript');
         foreach ($typoScriptNodes as $typoScriptNode) {
             $mergedTypoScriptCode .= $typoScriptNode->getProperty('sourceCode') . chr(10);
         }
     }
     return $this->typoScriptParser->parse($mergedTypoScriptCode, $typoScriptsPath);
 }
 /**
  * Remove all content and related data - for now. In the future we need some more sophisticated cleanup.
  *
  * @param boolean $confirmation
  * @return void
  */
 public function pruneCommand($confirmation = FALSE)
 {
     if ($confirmation === FALSE) {
         $this->outputLine('Please confirm that you really want to remove all sites and content from the database.');
         $this->outputLine('');
         $this->outputLine('Syntax:');
         $this->outputLine('  ./flow3 site:prune --confirmation TRUE');
         $this->quit(1);
     }
     $this->nodeRepository->removeAll();
     $this->workspaceRepository->removeAll();
     $this->domainRepository->removeAll();
     $this->siteRepository->removeAll();
     $this->outputLine('All sites and content have been removed.');
 }
 /**
  * @param string $pathAndFilename
  * @return void
  * @throws \TYPO3\FLOW3\Package\Exception\UnknownPackageException
  * @throws \TYPO3\FLOW3\Package\Exception\InvalidPackageStateException
  */
 public function importSitesFromFile($pathAndFilename)
 {
     $contentContext = $this->nodeRepository->getContext();
     $contentContext->setInvisibleContentShown(TRUE);
     $contentContext->setInaccessibleContentShown(TRUE);
     // no file_get_contents here because it does not work on php://stdin
     $fp = fopen($pathAndFilename, 'rb');
     $xmlString = '';
     while (!feof($fp)) {
         $xmlString .= fread($fp, 4096);
     }
     fclose($fp);
     $xml = new \SimpleXMLElement($xmlString);
     foreach ($xml->site as $siteXml) {
         $site = $this->siteRepository->findOneByNodeName((string) $siteXml['nodeName']);
         if ($site === NULL) {
             $site = new \TYPO3\TYPO3\Domain\Model\Site((string) $siteXml['nodeName']);
             $this->siteRepository->add($site);
         } else {
             $this->siteRepository->update($site);
         }
         $site->setName((string) $siteXml->properties->name);
         $site->setState((int) $siteXml->properties->state);
         $siteResourcesPackageKey = (string) $siteXml->properties->siteResourcesPackageKey;
         if ($this->packageManager->isPackageAvailable($siteResourcesPackageKey) === FALSE) {
             throw new \TYPO3\FLOW3\Package\Exception\UnknownPackageException('Package "' . $siteResourcesPackageKey . '" specified in the XML as site resources package does not exist.', 1303891443);
         }
         if ($this->packageManager->isPackageActive($siteResourcesPackageKey) === FALSE) {
             throw new \TYPO3\FLOW3\Package\Exception\InvalidPackageStateException('Package "' . $siteResourcesPackageKey . '" specified in the XML as site resources package is not active.', 1303898135);
         }
         $site->setSiteResourcesPackageKey($siteResourcesPackageKey);
         $rootNode = $contentContext->getWorkspace()->getRootNode();
         if ($rootNode->getNode('/sites') === NULL) {
             $rootNode->createSingleNode('sites');
         }
         $siteNode = $rootNode->getNode('/sites/' . $site->getNodeName());
         if ($siteNode === NULL) {
             $siteNode = $rootNode->getNode('/sites')->createSingleNode($site->getNodeName());
         }
         $siteNode->setContentObject($site);
         $this->parseNodes($siteXml, $siteNode);
     }
 }
 /**
  * Shows the specified node and takes visibility and access restrictions into
  * account.
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $node
  * @return string View output for the specified node
  */
 public function showWireframeAction(\TYPO3\TYPO3CR\Domain\Model\NodeInterface $node)
 {
     if (!$node->isAccessible()) {
         try {
             $this->authenticationManager->authenticate();
         } catch (\Exception $exception) {
         }
     }
     if (!$node->isAccessible() && !$this->nodeRepository->getContext()->isInaccessibleContentShown()) {
         $this->throwStatus(403);
     }
     if (!$node->isVisible() && !$this->nodeRepository->getContext()->isInvisibleContentShown()) {
         $this->throwStatus(404);
     }
     if ($node->getContentType() === 'TYPO3.Phoenix.ContentTypes:Shortcut') {
         $this->view->assign('wireframeMode', $node);
     }
     $this->nodeRepository->getContext()->setCurrentNode($node);
     $this->view->assign('value', $node);
     $this->view->setTypoScriptPath('wireframeMode');
     $this->response->setHeader('Cache-Control', 'public, s-maxage=600', FALSE);
 }
 /**
  * Wrap the $content identified by $node with the needed markup for
  * the backend.
  * $parameters can be used to further pass parameters to the content element.
  *
  * @param \TYPO3\TYPO3CR\Domain\Model\NodeInterface $node
  * @param string $typoscriptPath
  * @param string $content
  * @param boolean $isPage
  * @return string
  */
 public function wrapContentObject(\TYPO3\TYPO3CR\Domain\Model\NodeInterface $node, $typoscriptPath, $content, $isPage = FALSE)
 {
     $contentType = $node->getContentType();
     $tagBuilder = new \TYPO3\Fluid\Core\ViewHelper\TagBuilder('div');
     $tagBuilder->forceClosingTag(TRUE);
     if (!$node->isRemoved()) {
         $tagBuilder->setContent($content);
     }
     if (!$isPage) {
         $cssClasses = array('t3-contentelement');
         $cssClasses[] = str_replace(array(':', '.'), '-', strtolower($contentType->getName()));
         if ($node->isHidden()) {
             $cssClasses[] = 't3-contentelement-hidden';
         }
         if ($node->isRemoved()) {
             $cssClasses[] = 't3-contentelement-removed';
         }
         $tagBuilder->addAttribute('class', implode(' ', $cssClasses));
         $tagBuilder->addAttribute('id', 'c' . $node->getIdentifier());
     }
     try {
         $this->accessDecisionManager->decideOnResource('TYPO3_TYPO3_Backend_BackendController');
     } catch (\TYPO3\FLOW3\Security\Exception\AccessDeniedException $e) {
         return $tagBuilder->render();
     }
     $tagBuilder->addAttribute('typeof', 'typo3:' . $contentType->getName());
     $tagBuilder->addAttribute('about', $node->getContextPath());
     $this->addScriptTag($tagBuilder, '__workspacename', $node->getWorkspace()->getName());
     $this->addScriptTag($tagBuilder, '_removed', $node->isRemoved() ? 'true' : 'false', 'boolean');
     $this->addScriptTag($tagBuilder, '_typoscriptPath', $typoscriptPath);
     foreach ($contentType->getProperties() as $propertyName => $propertyConfiguration) {
         $dataType = isset($propertyConfiguration['type']) ? $propertyConfiguration['type'] : 'string';
         if ($propertyName[0] === '_') {
             $propertyValue = \TYPO3\FLOW3\Reflection\ObjectAccess::getProperty($node, substr($propertyName, 1));
         } else {
             $propertyValue = $node->getProperty($propertyName);
         }
         // Serialize boolean values to String
         if (isset($propertyConfiguration['type']) && $propertyConfiguration['type'] === 'boolean') {
             $propertyValue = $propertyValue ? 'true' : 'false';
         }
         // Serialize date values to String
         if ($propertyValue !== NULL && isset($propertyConfiguration['type']) && $propertyConfiguration['type'] === 'date') {
             $propertyValue = $propertyValue->format('Y-m-d');
         }
         // Serialize objects to JSON strings
         if (is_object($propertyValue) && $propertyValue !== NULL && isset($propertyConfiguration['type']) && $this->objectManager->isRegistered($propertyConfiguration['type'])) {
             $gettableProperties = \TYPO3\FLOW3\Reflection\ObjectAccess::getGettableProperties($propertyValue);
             $convertedProperties = array();
             foreach ($gettableProperties as $key => $value) {
                 if (is_object($value)) {
                     $entityIdentifier = $this->persistenceManager->getIdentifierByObject($value);
                     if ($entityIdentifier !== NULL) {
                         $value = $entityIdentifier;
                     }
                 }
                 $convertedProperties[$key] = $value;
             }
             $propertyValue = json_encode($convertedProperties);
             $dataType = 'jsonEncoded';
         }
         $this->addScriptTag($tagBuilder, $propertyName, $propertyValue, $dataType);
     }
     if (!$isPage) {
         // add CSS classes
         $this->addScriptTag($tagBuilder, '__contenttype', $contentType->getName());
     } else {
         $tagBuilder->addAttribute('id', 't3-page-metainformation');
         $tagBuilder->addAttribute('data-__sitename', $this->nodeRepository->getContext()->getCurrentSite()->getName());
         $tagBuilder->addAttribute('data-__siteroot', sprintf('/sites/%s@%s', $this->nodeRepository->getContext()->getCurrentSite()->getNodeName(), $this->nodeRepository->getContext()->getWorkspace()->getName()));
     }
     return $tagBuilder->render();
 }
 /**
  * @param string $workspaceName
  * @return \TYPO3\FLOW3\Persistence\QueryResultInterface
  */
 public function getUnpublishedNodes($workspaceName)
 {
     return $this->nodeRepository->findByWorkspace($this->workspaceRepository->findOneByName($workspaceName));
 }
 /**
  * Converts the specified node path into a Node.
  *
  * The node path must be an absolute context node path and can be specified as a string or as an array item with the
  * key "__contextNodePath". The latter case is for updating existing nodes.
  *
  * This conversion method does not support / allow creation of new nodes because new nodes should be created through
  * the createNode() method of an existing reference node.
  *
  * Also note that the context's "current node" is not affected by this object converter, you will need to set it to
  * whatever node your "current" node is, if any.
  *
  * All elements in the source array which start with two underscores (like __contextNodePath) are specially treated
  * by this converter.
  *
  * All elements in the source array which start with a *single underscore (like _hidden) are *directly* set on the Node
  * object.
  *
  * All other elements, not being prefixed with underscore, are properties of the node.
  *
  * @param string|array $source Either a string or array containing the absolute context node path which identifies the node. For example "/sites/mysitecom/homepage/about@user-admin"
  * @param string $targetType not used
  * @param array $subProperties not used
  * @param \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration not used
  * @return mixed An object or \TYPO3\FLOW3\Error\Error if the input format is not supported or could not be converted for other reasons
  * @throws \Exception
  */
 public function convertFrom($source, $targetType, array $subProperties = array(), \TYPO3\FLOW3\Property\PropertyMappingConfigurationInterface $configuration = NULL)
 {
     if (is_string($source)) {
         $source = array('__contextNodePath' => $source);
     }
     if (!is_array($source) || !isset($source['__contextNodePath'])) {
         return new Error('Could not convert ' . gettype($source) . ' to Node object, a valid absolute context node path as a string or array is expected.', 1302879936);
     }
     preg_match(NodeInterface::MATCH_PATTERN_CONTEXTPATH, $source['__contextNodePath'], $matches);
     if (!isset($matches['NodePath'])) {
         return new Error('Could not convert array to Node object because the node path was invalid.', 1285162903);
     }
     $nodePath = $matches['NodePath'];
     if ($this->nodeRepository->getContext() === NULL) {
         $workspaceName = isset($matches['WorkspaceName']) ? $matches['WorkspaceName'] : 'live';
         $contentContext = new ContentContext($workspaceName);
         $this->nodeRepository->setContext($contentContext);
     } else {
         $contentContext = $this->nodeRepository->getContext();
         $workspaceName = $contentContext->getWorkspace()->getName();
     }
     if ($workspaceName !== 'live') {
         $contentContext->setInvisibleContentShown(TRUE);
         if ($configuration->getConfigurationValue('TYPO3\\TYPO3\\Routing\\NodeObjectConverter', self::REMOVED_CONTENT_SHOWN) === TRUE) {
             $contentContext->setRemovedContentShown(TRUE);
         }
     }
     $workspace = $contentContext->getWorkspace(FALSE);
     if (!$workspace) {
         return new Error(sprintf('Could not convert %s to Node object because the workspace "%s" as specified in the context node path does not exist.', $source['__contextNodePath'], $workspaceName), 1285162905);
     }
     $currentAccessModeFromContext = $contentContext->isInaccessibleContentShown();
     $contentContext->setInaccessibleContentShown(TRUE);
     $node = $contentContext->getNode($nodePath);
     $contentContext->setInaccessibleContentShown($currentAccessModeFromContext);
     if (!$node) {
         return new Error(sprintf('Could not convert array to Node object because the node "%s" does not exist.', $nodePath), 1285162908);
     }
     $contentTypeProperties = $node->getContentType()->getProperties();
     foreach ($source as $nodePropertyKey => $nodePropertyValue) {
         if (substr($nodePropertyKey, 0, 2) === '__') {
             continue;
         }
         if ($nodePropertyKey[0] === '_') {
             $propertyName = substr($nodePropertyKey, 1);
             // TODO: Hack: we need to create DateTime objects for some properties of Node
             if (($propertyName === 'hiddenBeforeDateTime' || $propertyName === 'hiddenAfterDateTime') && is_string($nodePropertyValue)) {
                 if ($nodePropertyValue !== '') {
                     $nodePropertyValue = \DateTime::createFromFormat('!Y-m-d', $nodePropertyValue);
                 } else {
                     $nodePropertyValue = NULL;
                 }
             }
             \TYPO3\FLOW3\Reflection\ObjectAccess::setProperty($node, $propertyName, $nodePropertyValue);
         } else {
             if (!isset($contentTypeProperties[$nodePropertyKey])) {
                 throw new \Exception('TODO: content type XY does not have a property YY according to the schema');
             }
             if (isset($contentTypeProperties[$nodePropertyKey]['type'])) {
                 $targetType = $contentTypeProperties[$nodePropertyKey]['type'];
                 if ($this->objectManager->isRegistered($targetType)) {
                     $nodePropertyValue = $this->propertyMapper->convert(json_decode($nodePropertyValue, TRUE), $targetType);
                 }
             }
             $node->setProperty($nodePropertyKey, $nodePropertyValue);
         }
     }
     return $node;
 }