Getting data from the Model

This is getting $posts directly from your model:
PHP:
$posts = $this->getModelFromCache('Andy_ShowDeleted_Model_ShowDeleted')->getDeletedPosts();

This is fetching $posts from XenForo_Model_Post. The function getDeletedPosts() is initially not there. But you extended XenForo_Model_Post with Andy_ShowDeleted_Model_Post, so all your Andy_ShowDeleted_Model_Post functions are now accessible from XenForo_Model_Post:
PHP:
$posts = $this->getModelFromCache('XenForo_Model_Post')->getDeletedPosts();
 
Last edited:
I have another suggestion, to put the super admin assertion in _preDispatch which should be executed before the whole class is executed:

PHP:
class Andy_ShowDeleted_ControllerPublic_ShowDeleted extends XenForo_ControllerPublic_Abstract{

  protected function _preDispatch($action)
   {
     XenForo_Visitor::getInstance()->isSuperAdmin();
  }


public function actionIndex()
{

//########################################
// get data

If that would work, it is definitely more elegant.
 
Post #41 is such good information to know.

So which code should I use, what is the normal convention?
 
Not sure if @Jeremy meant the model or the controller with the _predispatch.

Is it important to have a listener also setup for the Controller? If yes, do this:

1. add a function to the listener
PHP:
<?php
class Andy_ShowDeleted_Listener{
public static function loadClassModel($class, array &$extend)
{$extend[] = 'Andy_ShowDeleted_Model_Post';
}
public static function loadClassController($class, array &$extend)
{$extend[] = 'Andy_ShowDeleted_ControllerPublic_ShowDeleted';
}
}
?>

2. add a listener in ACP
PHP:
load_class_controller
hint:XenForo_ControllerPublic_Abstract
Listener: Andy_ShowDeleted_Listener::loadClassController

It might be possible, that the superAdmin function is not correctly working in _preDispatch();
 
OK I think you have to change this function to something else, but I do not know what
PHP:
  protected function _preDispatch($action)
 {XenForo_Visitor::getInstance()->isSuperAdmin();
 }
 
This is a better code:

PHP:
  protected function _preDispatch($action)
{

    if (!XenForo_Visitor::getInstance()->isSuperAdmin())
     {
       throw $this->getNoPermissionResponseException();
     }
}

So not only it is more elegant as the permissions are not checked in the action functions, but they are checked for all functions in _preDispatch which is always executed before all other functions - you also get an already phrased nice "you do not have the permission to do this or that" error message.
 
ShowDeleted.php

PHP:
<?php

class Andy_ShowDeleted_ControllerPublic_ShowDeleted extends XenForo_ControllerPublic_Abstract
{	
	protected function _preDispatch($action)
	{
		if (!XenForo_Visitor::getInstance()->isSuperAdmin())
		{
			throw $this->getNoPermissionResponseException();
		}
	} 
	
	public function actionIndex()
	{				
		//########################################
		// get data
		
		// this is fetching $posts from XenForo_Model_Post 
		// the function getDeletedPosts() is initially not there
		// we extended XenForo_Model_Post with Andy_ShowDeleted_Model_Post
		// all Andy_ShowDeleted_Model_Post functions are now accessible from XenForo_Model_Post		
		
		// get deleted post_id's
        $posts = $this->getModelFromCache('XenForo_Model_Post')->getDeletedPosts();	
		
		// get deleted thread_id's
		$threads = $this->getModelFromCache('XenForo_Model_Thread')->getThreads(
			array('discussion_state' => 'deleted', 
			array('order' => 'thread_id', 
			'orderDirection' => 'DESC',
			array('limit' => 50,)))
		);
				
		//########################################
		// display data		
		
		// $viewParams must be an array
		$viewParams = array('posts' => $posts,'threads' => $threads,
		); 
		
		// send to template for display
		return $this->responseView('Andy_ShowDeleted_ViewPublic_ShowDeleted', 'andy_showdeleted', $viewParams);
	}
}

?>
 
So I assume the listener for load_class_controller isn't needed because the Route Prefix takes care of loading the ShowDeleted.php file.
 
One small problem. The order direction doesn't work.

PHP:
        // get deleted thread_id's
        $threads = $this->getModelFromCache('XenForo_Model_Thread')->getThreads(
            array('discussion_state' => 'deleted',
            array('order' => 'thread_id',
            array('orderDirection' => 'DESC',
            array('limit' => 50,))))
        );

Looking at the xF code it appears there's no provision for this.

PHP:
    public function getThreads(array $conditions, array $fetchOptions = array())
    {
        $whereConditions = $this->prepareThreadConditions($conditions, $fetchOptions);

        $sqlClauses = $this->prepareThreadFetchOptions($fetchOptions);
        $limitOptions = $this->prepareLimitFetchOptions($fetchOptions);

        $forceIndex = (!empty($fetchOptions['forceThreadIndex']) ? 'FORCE INDEX (' . $fetchOptions['forceThreadIndex'] . ')' : '');

        return $this->fetchAllKeyed($this->limitQueryResults(
            '
                SELECT thread.*
                    ' . $sqlClauses['selectFields'] . '
                FROM xf_thread AS thread ' . $forceIndex . '
                ' . $sqlClauses['joinTables'] . '
                WHERE ' . $whereConditions . '
                ' . $sqlClauses['orderClause'] . '
            ', $limitOptions['limit'], $limitOptions['offset']
        ), 'thread_id');
    }
 
This is doing the ordering: ' . $sqlClauses['orderClause'] . '

... and the variable is defined here: $sqlClauses = $this->prepareThreadFetchOptions($fetchOptions);

PHP:
  public function prepareThreadFetchOptions(array $fetchOptions)
   {
     $selectFields = '';
     $joinTables = '';
     $orderBy = '';

     if (!empty($fetchOptions['order']))
     {
       $orderBySecondary = '';

       switch ($fetchOptions['order'])
       {
         case 'title':
         case 'post_date':
         case 'view_count':
           $orderBy = 'thread.' . $fetchOptions['order'];
           break;

         case 'reply_count':
         case 'first_post_likes':
           $orderBy = 'thread.' . $fetchOptions['order'];
           $orderBySecondary = ', thread.last_post_date DESC';
           break;

         case 'last_post_date':
         default:
           $orderBy = 'thread.last_post_date';
       }
       if (!isset($fetchOptions['orderDirection']) || $fetchOptions['orderDirection'] == 'desc')
       {
         $orderBy .= ' DESC';
       }
       else
       {
         $orderBy .= ' ASC';
       }

       $orderBy .= $orderBySecondary;
     }

There is no mention of thread_id, but you can use post_date. So this might work
PHP:
  $threads = $this->getModelFromCache('XenForo_Model_Thread')->getThreads(
array('discussion_state' => 'deleted',
array('order' => 'post_date',
array('orderDirection' => 'DESC',
array('limit' => 50,))))
);

Order direction DESC is always set if you do not specify it as ASC (if (!isset($fetchOptions['orderDirection'])) So you can write this:

PHP:
  $threads = $this->getModelFromCache('XenForo_Model_Thread')->getThreads(
    array('discussion_state' => 'deleted'),
    array(
        'order' => 'post_date',
        'limit' => 50
    )
);

You did something wrong with having too much subarrays. getThreads gets two arrays:

PHP:
  public function getThreads(array $conditions, array $fetchOptions = array())
   {

As a side note, you could order the returned array in php, this is more convenient than doing that in templates. But the ordering should be done in the model.
 
Last edited:
This worked perfect! Thank you, Marcus.

PHP:
		// get deleted thread_id's
		$threads = $this->getModelFromCache('XenForo_Model_Thread')->getThreads(
			array('discussion_state' => 'deleted'),
			array(
			'order' => 'thread_id',
			'limit' => 50
			)
		);
 
ShowDeleted.php

PHP:
<?php

class Andy_ShowDeleted_ControllerPublic_ShowDeleted extends XenForo_ControllerPublic_Abstract
{	
	protected function _preDispatch($action)
	{
		if (!XenForo_Visitor::getInstance()->isSuperAdmin())
		{
			throw $this->getNoPermissionResponseException();
		}
	} 
	
	public function actionIndex()
	{				
		//########################################
		// get data
		
		// this is fetching $posts from XenForo_Model_Post 
		// the function getDeletedPosts() is initially not there
		// we extended XenForo_Model_Post with Andy_ShowDeleted_Model_Post
		// all Andy_ShowDeleted_Model_Post functions are now accessible from XenForo_Model_Post		
		
		// get deleted post_id's
        $posts = $this->getModelFromCache('XenForo_Model_Post')->getDeletedPosts();	
		
		// the function getThreads is located in library/Xenforo/Model/Thread.php
		// getThreads gets two arrays:
		// array($conditions) and array($fetchOptions)
		
		// get deleted thread_id's
		$threads = $this->getModelFromCache('XenForo_Model_Thread')->getThreads(
			array('discussion_state' => 'deleted'),
			array(
			'order' => 'thread_id',
			'limit' => 50
			)
		); 
				
		//########################################
		// display data		
		
		// $viewParams must be an array
		$viewParams = array('posts' => $posts,'threads' => $threads,
		); 
		
		// send to template for display
		return $this->responseView('Andy_ShowDeleted_ViewPublic_ShowDeleted', 'andy_showdeleted', $viewParams);
	}
}

?>
 
You have to change the order to post_date like this:

PHP:
$threads = $this->getModelFromCache('XenForo_Model_Thread')->getThreads(
array('discussion_state' => 'deleted'),
array('order' => 'post_date','limit' => 50)
);
 
Top Bottom