XF 2.1 Create a new url pattern for some threads without using route filters

djgxp

New member
I'm doing some development on a huge forum with about 3.5 million threads.
I have an extended class for XF:Thread in an addon that is adding a new field is_faq which is a boolean.

I have about 6000 urls to convert to /faq/... instead of /threads/...
First, in my extended class, just before the parent action, I was adding route filters if it where not existing for threads having 1 in my is_faq field and it was working.

Some flagged threads where well redirected to /faq/... instead of /threads/... .

But my problem is that when I reached about 5000 urls in route filter table, my Xenforo forum became dramatically slow because for each urls built in the page, it was doing 5000 preg_replace and about 10 million on a page then.

So as this is not possible this way, I want to avoid using route filters, maybe creating a new route which would take care about my DB field is_faq.

Is that possible ? (so that my forum listings would build well /faq/... links for the flagged threads and without using route filters. )

---
Or another suggestion would be to rework/improve the Router::applyRouteFilterToUrl method in order to avoid this CPU load due to the number of preg_replace done for 1 link.
 
Last edited:

djgxp

New member
Ok so I found my answer. We have overwritten assertCanonicalUrl method of the Thread class so that it can take care of the flag set in database.
 

djgxp

New member
Here is my solution:
  • Create a new addon MyNewAddon (for example)
  • Create a Listener.php with a xfThreadStructure method and add it in the admin panel in the Development tab in Code event listeners mapped to your addon:

PHP:
<?php
# File: Listener.php
namespace MyNewAddon;

use XF\Mvc\Entity\Entity;

class Listener
{
    public static function xfThreadStructure(\XF\Mvc\Entity\Manager $em, \XF\Mvc\Entity\Structure &$structure)
    {
        $structure->columns['is_faq'] = ['type' => Entity::INT, 'changeLog' => false, 'default' => 0];
    }
}

196574

  • Create an extended Thread class and add it in the admin panel in the Development tab in Class extensions:
PHP:
<?php
# File: XF/Pub/Controller/Thread.php

namespace MyNewAddon\XF\Pub\Controller;

use XF\Mvc\FormAction;
use XF\Mvc\ParameterBag;
use XF\Mvc\Reply\AbstractReply;

class Thread extends XFCP_Thread
{
    protected $isFaq = 0;

    public function actionIndex(ParameterBag $params) {
        // FAQ threads.
        $thread = $this->assertViewableThread($params->thread_id, $this->getThreadViewExtraWith());
        $this->isFaq = $thread->is_faq;
        return parent::actionIndex($params);
    }

    public function assertCanonicalUrl($linkUrl) {
        $basePath = $this->request->getBasePath();
        $requestUri = $this->request->getRequestUri();

        $routeBase = ltrim(substr($requestUri, strlen($basePath)), '/');
        if(property_exists($this, 'isFaq') && $this->isFaq && (strpos($routeBase, 'faq/') === 0 || strpos($routeBase, 'threads/') === 0)) {
            // we have an FAQ.
            $linkUrl = str_replace('/threads', '/faq', $linkUrl);
        }

        return parent::assertCanonicalUrl($linkUrl);
    }
}

Then either you can add the field to MySQL DB or add a Setup.php field to your addon to add this field on install:
SQL:
ALTER TABLE `xf_thread` ADD `is_faq` INT(1) NOT NULL DEFAULT '0';

So if you want your thread to work on /faq/.... instead of /threads/.... patterns, you just need to flag it to 1 in the DB.
 
Top