Sort columns in joomla via populateState method

5.7k views Asked by At

I'm sorting table columns in Joomla Backend. I adjust settings according to this tutorial.

As we can see it is suggested to override populateState method and manually obtain sorting options.

public function populateState() {
    $filter_order = JRequest::getCmd('filter_order');
    $filter_order_Dir = JRequest::getCmd('filter_order_Dir');

    $this->setState('filter_order', $filter_order);
    $this->setState('filter_order_Dir', $filter_order_Dir);
}

But I noticed that the native component com_content does not set these options explicitly in the model file administrator/components/com_content/models/articles.php.

protected function populateState($ordering = null, $direction = null)
{
    // Initialise variables.
    $app = JFactory::getApplication();
    $session = JFactory::getSession();

............................................
............................................
............................................

    // List state information.
    parent::populateState('a.title', 'asc');
} 

Instead it just invokes parent populateState. And in fact JModelList::populateState() includes this:

protected function populateState($ordering = null, $direction = null)
{
    // If the context is set, assume that stateful lists are used.
    if ($this->context) {
        $app = JFactory::getApplication();

.....................................
.....................................
.....................................

        $value = $app->getUserStateFromRequest($this->context.'.ordercol', 'filter_order', $ordering);
        if (!in_array($value, $this->filter_fields)) {
            $value = $ordering;
            $app->setUserState($this->context.'.ordercol', $value);
        }
        $this->setState('list.ordering', $value);

        // Check if the ordering direction is valid, otherwise use the incoming value.
        $value = $app->getUserStateFromRequest($this->context.'.orderdirn', 'filter_order_Dir', $direction);
        if (!in_array(strtoupper($value), array('ASC', 'DESC', ''))) {
            $value = $direction;
            $app->setUserState($this->context.'.orderdirn', $value);
        }
        $this->setState('list.direction', $value);
    }
    else {
        $this->setState('list.start', 0);
        $this->state->set('list.limit', 0);
    }
}

So I'm trying to imitate the code of the native com_content. Thus I assume that

class CompViewData extends JView
{

function display($tpl = null)
{
    $this->state = $this->get('State');

Will invoke parent JModelList::populateState() (so I'm not overriding it in the modal class) and set $this->setState('list.ordering', $value);. But for some reason when I invoke $this->state->get() in getListQuery() to build my SQL query with ordering

protected function getListQuery()
{

    $orderCol   = $this->state->get('list.ordering', 'id');
    $orderDirn  = $this->state->get('list.direction', 'asc');

This variables happen to be not defined.

What am I missing? I assume it is somehow connected with proper user session, but I don't have evidence whatsoever.

2

There are 2 answers

1
Jason On BEST ANSWER

After just coming across the same issue I found that, as you said, the superclass populateState() does indeed have the behaviour defined. However, it also does a check to ensure your field is in the "whitelist".

if (!in_array($value, $this->filter_fields))

If you look at com_content you will see this section at the top of the model class (in your case models/articles.php):

public function __construct($config = array())
{
    if (empty($config['filter_fields']))
    {
        $config['filter_fields'] = array(
            'id', 'a.id',
            'title', 'a.title',
             //...(more fields here)
            'publish_up', 'a.publish_up',
            'publish_down', 'a.publish_down',
        );

        $app = JFactory::getApplication();
        $assoc = isset($app->item_associations) ? $app->item_associations : 0;
        if ($assoc)
        {
            $config['filter_fields'][] = 'association';
        }
    }

    parent::__construct($config);
}

You will need to include this section so that the ModelList class knows that the 'ordering' field is in the whitelist. Obviously substitute the fields with those on which you wish to filter.

1
Sergey Romanov On

The Joomla JModelList defines populateState like this

protected function populateState($ordering = null, $direction = null)

It means that if you do not have populateState override in you class, this will be called but it gets no values. The minimum requirement is to set default values if you want to use ordering. You may completely delete this method from your class if you are not planning to use ordering at all.

So, minimum what you need is to interpolate in your class

protected function populateState($ordering = null, $direction = null) {
    parent::populateState('id', 'ACS');
}

Otherwise you will not get anything in $state->get() or $this->state->get() unless you click on ordering column. Then parent's populateState will take variables from request.