SitemapBuilder.php 4.66 KB
Newer Older
1 2 3 4 5 6
<?php
namespace Ttree\Neos\Sitemap\Service;

use Tackk\Cartographer\ChangeFrequency;
use Tackk\Cartographer\Sitemap;
use Ttree\Neos\Sitemap\Domain\Model\SitemapDefinition;
7 8
use TYPO3\Eel\EelEvaluatorInterface;
use TYPO3\Eel\Utility;
9 10 11 12 13 14 15 16
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Http\Request;
use TYPO3\Flow\Http\Response;
use TYPO3\Flow\Http\Uri;
use TYPO3\Flow\Mvc\ActionRequest;
use TYPO3\Flow\Mvc\Controller\Arguments;
use TYPO3\Flow\Mvc\Controller\ControllerContext;
use TYPO3\Flow\Mvc\Routing\UriBuilder;
17
use TYPO3\Flow\Utility\Arrays;
18 19 20 21 22 23 24 25 26
use TYPO3\Neos\Domain\Repository\SiteRepository;
use TYPO3\Neos\Service\LinkingService;
use TYPO3\TYPO3CR\Domain\Model\NodeInterface;
use TYPO3\TYPO3CR\Domain\Service\ContextFactoryInterface;

/**
 * @Flow\Scope("singleton")
 * @api
 */
27 28
class SitemapBuilder implements SitemapBuilderInterface
{
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

    /**
     * @var ContextFactoryInterface
     * @Flow\Inject
     */
    protected $contextFactory;

    /**
     * @var SiteRepository
     * @Flow\Inject
     */
    protected $siteRepository;

    /**
     * @Flow\Inject
     * @var LinkingService
     */
    protected $linkingService;

    /**
     * @Flow\Inject
     * @var UriBuilder
     */
    protected $uriBuilder;

54 55 56 57 58 59
    /**
     * @Flow\Inject
     * @var EelEvaluatorInterface
     */
    protected $eelEvaluator;

60 61 62 63
    /**
     * @param SitemapDefinition $definiton
     * @return string
     */
64 65
    public function build(SitemapDefinition $definiton)
    {
66 67 68 69 70 71 72
        $preset = $definiton->getPreset();
        $processedUri = [];
        $sitemap = new Sitemap();

        $context = $this->createContext('live', $definiton->getSiteNodeName());
        $controllerContext = $this->createControllerContext($definiton->getBaseUrl());

73
        foreach ($preset['includes'] as $queryLabel => $query) {
74
            $nodes = Utility::evaluateEelExpression($query, $this->eelEvaluator, ['node' => $context->getRootNode()]);
75
            /** @var NodeInterface $node */
76
            foreach ($nodes as $node) {
77 78 79
                if ($this->needToSkipNode($preset, $node)) {
                    continue;
                }
80
                $uri = $this->linkingService->createNodeUri($controllerContext, $node, null, 'html', true);
81 82 83 84 85 86
                $hash = md5($uri);
                if (isset($processedUri[$hash])) {
                    continue;
                }
                $lastPublicationDateTime = $node->getNodeData()->getLastPublicationDateTime() ?: $node->getNodeData()->getLastModificationDateTime();
                $sitemap->add($uri, $lastPublicationDateTime ? $lastPublicationDateTime->format('Y-m-d') : null, ChangeFrequency::WEEKLY, 1.0);
87
                $processedUri[$hash] = true;
88 89 90 91 92 93 94 95 96 97 98
            }
        }

        return (string)$sitemap;
    }

    /**
     * @param array $preset
     * @param NodeInterface $node
     * @return boolean
     */
99 100
    protected function needToSkipNode(array $preset, NodeInterface $node)
    {
101
        if (trim($node->getProperty('uriPathSegment')) === '') {
102
            return true;
103 104 105
        }
        $skipNodeTypes = Arrays::getValueByPath($preset, 'skipNodeTypes') ?: [];
        foreach ($skipNodeTypes as $nodeType => $nodeTypeStatus) {
106
            if ($nodeTypeStatus !== true) {
107 108
                continue;
            }
109 110
            if ($node->getNodeType()->isOfType($nodeType) === true) {
                return true;
111 112
            }
        }
113
        return false;
114 115 116 117 118 119
    }

    /**
     * @param string $baseUrl
     * @return ControllerContext
     */
120 121
    protected function createControllerContext($baseUrl)
    {
122 123 124 125 126 127 128 129 130 131 132 133 134 135
        $httpRequest = Request::create(new Uri($baseUrl));
        $response = new Response();
        $arguments = new Arguments([]);
        return new ControllerContext(new ActionRequest($httpRequest), $response, $arguments, $this->uriBuilder);
    }

    /**
     * Creates a content context for given workspace and language identifiers
     *
     * @param string $workspaceName
     * @param string $siteNodeName
     * @param array $languageIdentifiers
     * @return \TYPO3\TYPO3CR\Domain\Service\Context
     */
136 137
    protected function createContext($workspaceName, $siteNodeName, array $languageIdentifiers = null)
    {
138
        $site = $this->siteRepository->findOneByNodeName($siteNodeName);
139
        $contextProperties = [
140 141
            'workspaceName' => $workspaceName,
            'currentSite' => $site,
142 143 144 145 146 147 148
            'invisibleContentShown' => true,
            'inaccessibleContentShown' => true
        ];
        if ($languageIdentifiers !== null) {
            $contextProperties = array_merge($contextProperties, [
                'dimensions' => ['language' => $languageIdentifiers]
            ]);
149 150 151 152 153
        }
        return $this->contextFactory->create($contextProperties);
    }


154
}