src/Kunstmaan/NodeBundle/EventListener/NodeTranslationListener.php
private function ensureUniqueUrl(NodeTranslation $translation, EntityManagerInterface $em, array $flashes = [])
    {
        // Can't use GetRef here yet since the NodeVersions aren't loaded yet for some reason.
        $nodeVersion = $translation->getPublicNodeVersion();
        $page = $em->getRepository($nodeVersion->getRefEntityName())
            ->find($nodeVersion->getRefId());

        if (null === $page) {
            return false;
        }

        $isStructureNode = $page->isStructureNode();

        // If it's a StructureNode the slug and url should be empty.
        if ($isStructureNode) {
            $translation->setSlug('');
            $translation->setUrl($translation->getFullSlug());

            return true;
        }

        /* @var NodeTranslationRepository $nodeTranslationRepository */
        $nodeTranslationRepository = $em->getRepository(NodeTranslation::class);

        if ($translation->getUrl() === $translation->getFullSlug()) {
            $this->logger->debug(
                sprintf(
                    'Evaluating URL for NT %s getUrl: "%s" getFullSlug: "%s"',
                    $translation->getId(),
                    $translation->getUrl(),
                    $translation->getFullSlug()
                )
            );

            return false;
        }

        // Adjust the URL.
        $translation->setUrl($translation->getFullSlug());

        // Find all translations with this new URL, whose nodes are not deleted.
        $translations = $nodeTranslationRepository->getAllNodeTranslationsForUrl(
            $translation->getUrl(),
            $translation->getLang(),
            false,
            $translation,
            $this->domainConfiguration->getRootNode()
        );

        $this->logger->debug(
            sprintf(
                'Found %s node(s) that math url "%s"',
                \count($translations),
                $translation->getUrl()
            )
        );

        $translationsWithSameUrl = [];

        /** @var NodeTranslation $trans */
        foreach ($translations as $trans) {
            if (!$this->pagesConfiguration->isStructureNode($trans->getPublicNodeVersion()->getRefEntityName())) {
                $translationsWithSameUrl[] = $trans;
            }
        }

        if (\count($translationsWithSameUrl) > 0) {
            $oldUrl = $translation->getFullSlug();
            $translation->setSlug(
                $this->slugifier->slugify(
                    $this->incrementString($translation->getSlug())
                )
            );
            $newUrl = $translation->getFullSlug();

            $message = sprintf(
                'The URL of the page has been changed from %s to %s since another page already uses this URL',
                $oldUrl,
                $newUrl
            );
            $this->logger->info($message);
            $flashes[] = $message;

            $this->ensureUniqueUrl($translation, $em, $flashes);
        } elseif (\count($flashes) > 0 && $this->isInRequestScope()) {
            // No translations found so we're certain we can show this message.
            $flash = current(\array_slice($flashes, -1));
            $this->flashBag->add(FlashTypes::WARNING, $flash);
        }

        return true;
    }
private function ensureUniqueUrl(NodeTranslation $translation, EntityManagerInterface $em, array $flashes = [])
    {
        // Can't use GetRef here yet since the NodeVersions aren't loaded yet for some reason.
        $nodeVersion = $translation->getPublicNodeVersion();
        $page = $em->getRepository($nodeVersion->getRefEntityName())
            ->find($nodeVersion->getRefId());

        if (null === $page) {
            return false;
        }

        $isStructureNode = $page->isStructureNode();

        // If it's a StructureNode the slug and url should be empty.
        if ($isStructureNode) {
            $translation->setSlug('');
            $translation->setUrl($translation->getFullSlug());

            return true;
        }

        /* @var NodeTranslationRepository $nodeTranslationRepository */
        $nodeTranslationRepository = $em->getRepository(NodeTranslation::class);

        if ($translation->getUrl() === $translation->getFullSlug()) {
            $this->logger->debug(
                sprintf(
                    'Evaluating URL for NT %s getUrl: "%s" getFullSlug: "%s"',
                    $translation->getId(),
                    $translation->getUrl(),
                    $translation->getFullSlug()
                )
            );

            return false;
        }

        // Adjust the URL.
        $translation->setUrl($translation->getFullSlug());

        // Find all translations with this new URL, whose nodes are not deleted.
        $translations = $nodeTranslationRepository->getAllNodeTranslationsForUrl(
            $translation->getUrl(),
            $translation->getLang(),
            false,
            $translation,
            $this->domainConfiguration->getRootNode()
        );

        $this->logger->debug(
            sprintf(
                'Found %s node(s) that math url "%s"',
                \count($translations),
                $translation->getUrl()
            )
        );

        $translationsWithSameUrl = [];

        /** @var NodeTranslation $trans */
        foreach ($translations as $trans) {
            if (!$this->pagesConfiguration->isStructureNode($trans->getPublicNodeVersion()->getRefEntityName())) {
                $translationsWithSameUrl[] = $trans;
            }
        }

        if (\count($translationsWithSameUrl) > 0) {
            $oldUrl = $translation->getFullSlug();
            $translation->setSlug(
                $this->slugifier->slugify(
                    $this->incrementString($translation->getSlug())
                )
            );
            $newUrl = $translation->getFullSlug();

            $message = sprintf(
                'The URL of the page has been changed from %s to %s since another page already uses this URL',
                $oldUrl,
                $newUrl
            );
            $this->logger->info($message);
            $flashes[] = $message;

            $this->ensureUniqueUrl($translation, $em, $flashes);
        } elseif (\count($flashes) > 0 && $this->isInRequestScope()) {
            // No translations found so we're certain we can show this message.
            $flash = current(\array_slice($flashes, -1));
            $this->flashBag->add(FlashTypes::WARNING, $flash);
        }

        return true;
    }
private function ensureUniqueUrl ( NodeTranslation $ translation , EntityManagerInterface $ em , array $ flashes = [ ] ) { // Can't use GetRef here yet since the NodeVersions aren't loaded yet for some reason. $ nodeVersion = $ translation -> getPublicNodeVersion ( ) ; $ page = $ em -> getRepository ( $ nodeVersion -> getRefEntityName ( ) ) -> find ( $ nodeVersion -> getRefId ( ) ) ; if ( null === $ page ) { return false ; } $ isStructureNode = $ page -> isStructureNode ( ) ; // If it's a StructureNode the slug and url should be empty. if ( $ isStructureNode ) { $ translation -> setSlug ( '' ) ; $ translation -> setUrl ( $ translation -> getFullSlug ( ) ) ; return true ; } /* @var NodeTranslationRepository $nodeTranslationRepository */ $ nodeTranslationRepository = $ em -> getRepository ( NodeTranslation :: class ) ; if ( $ translation -> getUrl ( ) === $ translation -> getFullSlug ( ) ) { $ this -> logger -> debug ( sprintf ( 'Evaluating URL for NT %s getUrl: "%s" getFullSlug: "%s"' , $ translation -> getId ( ) , $ translation -> getUrl ( ) , $ translation -> getFullSlug ( ) ) ) ; return false ; } // Adjust the URL. $ translation -> setUrl ( $ translation -> getFullSlug ( ) ) ; // Find all translations with this new URL, whose nodes are not deleted. $ translations = $ nodeTranslationRepository -> getAllNodeTranslationsForUrl ( $ translation -> getUrl ( ) , $ translation -> getLang ( ) , false , $ translation , $ this -> domainConfiguration -> getRootNode ( ) ) ; $ this -> logger -> debug ( sprintf ( 'Found %s node(s) that math url "%s"' , \ count ( $ translations ) , $ translation -> getUrl ( ) ) ) ; $ translationsWithSameUrl = [ ] ; /** @var NodeTranslation $trans */ foreach ( $ translations as $ trans ) { if ( ! $ this -> pagesConfiguration -> isStructureNode ( $ trans -> getPublicNodeVersion ( ) -> getRefEntityName ( ) ) ) { $ translationsWithSameUrl [ ] = $ trans ; } } if ( \ count ( $ translationsWithSameUrl ) > 0 ) { $ oldUrl = $ translation -> getFullSlug ( ) ; $ translation -> setSlug ( $ this -> slugifier -> slugify ( $ this -> incrementString ( $ translation -> getSlug ( ) ) ) ) ; $ newUrl = $ translation -> getFullSlug ( ) ; $ message = sprintf ( 'The URL of the page has been changed from %s to %s since another page already uses this URL' , $ oldUrl , $ newUrl ) ; $ this -> logger -> info ( $ message ) ; $ flashes [ ] = $ message ; $ this -> ensureUniqueUrl ( $ translation , $ em , $ flashes ) ; } elseif ( \ count ( $ flashes ) > 0 && $ this -> isInRequestScope ( ) ) { // No translations found so we're certain we can show this message. $ flash = current ( \ array_slice ( $ flashes , - 1 ) ) ; $ this -> flashBag -> add ( FlashTypes :: WARNING , $ flash ) ; } return true ; }
A function that checks the URL and sees if it's unique.
It's allowed to be the same when the node is a StructureNode.
When a node is deleted it needs to be ignored in the check.
Offline nodes need to be included as well.

It sluggifies the slug, updates the URL
and checks all existing NodeTranslations ([1]), excluding itself. If a
URL existsthat has the same url. If an existing one is found the slug is
modified, the URL is updated and the check is repeated until no prior
urls exist.

NOTE: We need a way to tell if the slug has been modified or not.
NOTE: Would be cool if we could increment a number after the slug. Like
check if it matches -v# and increment the number.

[1] For all languages for now. The issue is that we need a way to know
if a node's URL is prepended with the language or not. For now both
scenarios are possible so we check for all languages.

@param NodeTranslation        $translation Reference to the NodeTranslation.
This is modified in place.
@param EntityManagerInterface $em          The entity manager
@param array                  $flashes     The flash messages array

@return bool
A function that checks the URL and sees if it s unique . It s allowed to be the same when the node is a StructureNode . When a node is deleted it needs to be ignored in the check . Offline nodes need to be included as well .