• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

Model returns list of thread ID's, what now?

Marcel

Active member
#1
Im on my way with this plugin

At the moment I have the following

A ControllerPublic with the following code

PHP:
<?php

class MaB_NewPosts_ControllerPublic_NewPosts extends XenForo_ControllerPublic_FindNew {
 
public function actionIndex()
{
    $threadIds = $this->getModelFromCache('MaB_NewPosts_Model_NewPosts')->getUnreadThreads();
    If (!$threadIds){
        return $this->responseMessage(new XenForo_Phrase('mab_np_noresults'));
    }

    // If we're at this point then     there must be results.
 
    $viewParams = array('threads' => $threadIds);
    return $this->responseView('MaB_NewPosts_ViewPublic_NewPosts', 'mab_np_main',$viewParams);
    }

 
}
and a model which extends XenForo_Model_Thread

PHP:
<?php

class MaB_NewPosts_Model_NewPosts extends XenForo_Model_Thread
{


/**
* Gets the IDs of threads
*
* @param integer $userId
* @return array List of thread IDs
*/
    public function getUnreadThreads()
    {
    return $this->_getDb()->fetchAll('
                    SELECT thread.*
                    FROM xf_thread AS thread
                    LEFT JOIN xf_node AS node ON
                        (node.node_id = thread.node_id)
                    LEFT JOIN xf_thread_read AS thread_read ON
                        (thread_read.thread_id = thread.thread_id AND thread_read.user_id = 1
                        AND thread_read.thread_read_date >= thread.last_post_date)
                    LEFT JOIN xf_forum_read AS forum_read ON
                        (forum_read.node_id = thread.node_id AND forum_read.user_id = 1
                        AND forum_read.forum_read_date >= thread.last_post_date)
                    WHERE thread_read.thread_read_date IS NULL
                    ORDER BY thread.last_post_date DESC
            LIMIT 50');
 
    }
}
Now this works. It returns an array $threads filled with the relevant (unread) thread ID's and all the fields from the xf_thread table corresponding to each row selected.

Now, I want to parse this into a viewable list of results.
I've passed it to my template (which is a copy of thread_list with some bumpf taken out )
This shows some of the data needed. However, it doesn't for example, pull out the thread starter avatar, the node title etc.
How would I add these? I understand theyre from a different table, and my controller and model don't retrieve this data....
I tried with very limited knowledge of SQL to add it to the query in the model, but got stuck.

I know the whole structure is very primitive, but it's something I plan on building on. Naturally there will be permissions checks, pagination of results etc.
I also tried extending both the ControllerPublic class and the Model class via the XFCP method, but it didn't work, so I hope this is the correct way to do it!
This is executed by a route prefix /newposts
I hope to build on this with newposts/discussion ..... newposts/images etc etc. Hence doing it via a route controller :)
 
Last edited:

Marcel

Active member
#3
Been looking at this again today. I've changed the ControllerPublic to extend XenForo_ControllerPublic_Thread
After the $threadIds array is filled with a list of thread_Id's I've then added the following

$threads = $this->getModelFromCache('XenForo_Model_Thread')->getThreadsbyIds($threadIds,$fetchOptions);

Then I was planning on returning $threads to the template, as I assumed that would have all the thread details in.
Nope...it actually returns a bigger list of threads (I think it's all of them).

So in a nutshell, after pulling a list of thread ID's, how do I then use that to pull last poster, avatar, replies, views node information, etc etc for each row.
 

Brogan

XenForo moderator
Staff member
#4
Have you tried dumping the param either in the php or the template to see what's available?

Zend_Debug::dump($param); or {xen:helper dump, $param}
 

Marcel

Active member
#5
Thanks Brogan. I did use the dump helper to have a look at the data passed back.
I've looked at Andy's plugin (thanks for that!), and it seems an update in the Model is the way to go.
I've modified the SQL statement, selecting
xf_user.user_id, xf_user.avatar_date
then adding
INNER JOIN xf_user ON xf_user.user_id = xf_thread.user_id

It works, so I'm now building it properly to pull correct visitor information, and then I'll work on the permissions etc.

Thank you both for your replies, much appreciated :)
I must say Andy, I'm learning alot from the threads you've started and the questions you've asked on what I assume is the same journey as I am on :)

One further question

My ControllerPublic extends XenForo_ControllerPublic_Thread
and my Model extends XenForo_Model_Thread. It all works, but Im not using the Class Proxy system for either.
When I do try to extend the XFCP etc etc, I get an error.
I can understand why this happens if I try and use the XFCP with the Controller, as I'm not actually hooking into anything with it, it's because I'm creating a new Controller.
Is this the right way to do it? Should I be extended a different controller other than Thread?
 

Brogan

XenForo moderator
Staff member
#6
If you are extending the thread controller then it should be: class Your_Class_ControllerPublic_Thread extends XFCP_Your_Class_ControllerPublic_Thread
 

Marcel

Active member
#7
I tried that but I just get the error

An exception occurred: Cannot load class using XFCP. Load the class using the correct loader first.
Am I right in thinking that this error is generated because it's expecting XenForo_ControllerPublic_Thread to already be loaded when it loads myaddon_ControllerPublic_Thread....and this plugin doesn't rely on that.

As I'm not actually building on any methods or functionality in XenForo_ControllerPublic_Thread, I shouldn't really be extending it.
The question is, I don't know what I should be extending.

All I'm doing is running a custom query using my thread model and returning a list of results.
I've not extended ControllerPublic_Search (as that was too messy and unnecessary).
 
Last edited:

Marcel

Active member
#9
This is the file structure
(Ignore the Option folder)
NewPostsStructure.jpg

Contents of ControllerPublic/NewPosts.php
PHP:
<?php

class MaB_NewPosts_ControllerPublic_NewPosts extends XenForo_ControllerPublic_Thread {

public function actionIndex()
{
    $threads = $this->getModelFromCache('MaB_NewPosts_Model_NewPosts')->getUnreadThreads();

    If (!$threads){
        return $this->responseMessage(new XenForo_Phrase('mab_np_noresults'));
    }
    $viewParams = array('threads' => $threads);
    return $this->responseView('MaB_NewPosts_ViewPublic_NewPosts', 'mab_np_results',$viewParams);
}

} // end class
Contents of Listener/Extend.php
PHP:
<?php
class MaB_NewPosts_Listener_Extend
{
    public static function loadClassController($class, array &$extend)
    {
        $extend[] = 'MaB_NewPosts_ControllerPublic_NewPosts';
    }

}
Contents of Listener/NavTabs.php
PHP:
<?php
class MaB_NewPosts_Listener_NavTabs
{
    public static function addNavTab(array &$extraTabs, $selectedTabId)
    {
        $extraTabs['NewPosts'] = array (
            'title' => new XenForo_Phrase('mab_np_newposts'),
            'href' => XenForo_Link::buildPublicLink('newposts'),
            'position' => 'end',
            'selected' =>  ($selectedTabId == 'newposts'),
            'linksTemplate' => 'mab_np_navtab'
        );

    }
}
Contents of Model/NewPosts.php
PHP:
<?php

class MaB_NewPosts_Model_NewPosts extends XenForo_Model_Thread
{
    public function getUnreadThreads()
    {
    $userId = '1';
    $maxResults = XenForo_Application::get ( 'options' )->get ( 'maximumSearchResults' );
    /* if $newPostsType = 'discussion'
    {
    }*/


    $extraConditions = "AND xf_thread.node_id = 8";
    //$extraConditions = "";
    return $this->_getDb()->fetchAll("
SELECT xf_thread.thread_id,
        xf_thread.title,
        xf_thread.reply_count,
        xf_thread.view_count,
        xf_thread.username,
        xf_node.title AS nodeTitle,
        xf_thread_user_post.post_count AS user_post_count,
        xf_user.user_id,
        xf_user.avatar_date
        FROM xf_thread
        INNER JOIN xf_node ON xf_node.node_id = xf_thread.node_id
        LEFT JOIN xf_thread_user_post
            ON (xf_thread_user_post.thread_id = xf_thread.thread_id
            AND xf_thread_user_post.user_id = " . $userId . ")
        INNER JOIN xf_user ON xf_user.user_id = xf_thread.user_id
        LEFT JOIN xf_thread_read
            ON (xf_thread_read.thread_id = xf_thread.thread_id AND xf_thread_read.user_id = " . $userId . "
            AND xf_thread_read.thread_read_date >= xf_thread.last_post_date)
        WHERE xf_thread_read.thread_read_date IS NULL
        " . $extraConditions . "
        ORDER BY xf_thread.view_count DESC
            LIMIT ?", $maxResults);

    }
}
Contents of Route/Prefix/NewPosts.php
PHP:
<?php



class MaB_NewPosts_Route_Prefix_NewPosts implements XenForo_Route_Interface

{



public function match($routePath, Zend_Controller_Request_Http $request, XenForo_Router $router)

{

//return $router->getRouteMatch('MaB_NewPosts_ControllerPublic_NewPosts', $routePath, 'newposts');

$action = $router->resolveActionWithIntegerParam($routePath, $request, 'search_id');

return $router->getRouteMatch('MaB_NewPosts_ControllerPublic_NewPosts', $action, 'newposts');

}



}
 

Marcel

Active member
#10
Sorry if there is something wrong in there. I've been changing it back and forth, I changed MaB_NewPosts_ControllerPublic_NewPosts, to MaB_NewPosts_ControllerPublic_Thread after your post above (I thought you could name the last part of the class anything you wanted until you posted, then thought "It's because I called it "NewPosts" instead of "Thread", so I changed it ......still didn't work, so I changed it back :))
 

Marcel

Active member
#14
Cheers. I'll rename it all now, if that's the proper way of doing it.
However, I'm still getting that error when I try and load it via the XFCP system.
I think it's because my listener isn't triggering because the thread controller is not being loaded.
So the question is, with the above code, what *should* I be listening for / extending?
 

Brogan

XenForo moderator
Staff member
#15
In the ACP you would have an event hint of: XenForo_ControllerPublic_Thread

Then just the standard listener code:
PHP:
public static function extendThreadController($class, array &$extend)
{
    $extend[] = 'CTA_FeaturedThreads_ControllerPublic_Thread';
}
 

Marcel

Active member
#16
Already tried that :) Still get the same error.
Infact, I think the correct way to do this would be to have no listener, and to extend XenForo_Controller_Abstract, no?
I'm not sure which Controller I should be hooking into/extending (If any)
 

Brogan

XenForo moderator
Staff member
#17
What does your add-on actually do?

Does it utilise the threads route?
Do you need to extend an existing function?
 

Marcel

Active member
#18
It doesn't, I've created my own route 'newposts'
Basically, it pulls a list of unread threads with different criteria.
At the moment, it does all forums, all threads with unread posts.
It will eventually have many choices which correspond to different sets of criteria
For example :

Link 1 will return all threads with unread posts from forum x and y.
Link 2 will return all threads with unread posts from forum y and z
Link 3 will return all threads with unread posts from forum y, and prefix 1
Link 4 will return all threads with zero replies from forum x, y and z with prefix 1

etc
Extending the search controller to do this was too difficult (as that was expecting searches from an input form, searching for particular data PLUS criteria)
The same with extending new-posts, I didn't think it was suitable for what I wanted to do.
Hence why I went down this path.
It has its own route prefix, and therefore it's own controller.
 

Marcel

Active member
#19
Actually, I've just been reading through the original Thread model.
I should be able to do this by using that, rather than my own model.

I could use the following functions :
getUnreadThreadIds, getThreadsByIds, prepareThreadFetchOptions