I want to add "natural sorting" functionality to Magento admin grid. I would like to understand how the Magento handles admin grid sorting so I know where to start. What functions/files etc. does Magento use to determine the order of values in the admin panel?
-
will you please explain more– Gopal PatelCommented Mar 19, 2017 at 11:46
-
I want to add a functionality like "natsort" in PHP, to admin panel sorting (catalog, sales, etc.) . There is very little info about this online. I found this code that in theory should help me: (magento.stackexchange.com/a/124324/51693), but I do not understand how to implement it.– Metal MathematicianCommented Mar 19, 2017 at 12:03
-
_build_sorter function, to be exact– Metal MathematicianCommented Mar 19, 2017 at 12:35
2 Answers
With grids in Magento, the database driver controls the sorting of data. The collection is passed the sort column and direction of sort (asc or desc) or the default is used. The data in the collection returned is output in that same order.
To change the sorting functionality in your own custom grid, you can just alter modify the _prepareCollection
method to adjust the collection to what order you want.
In my custom grid, I would probably do something like this:
class My_Module_Block_Adminhtml_Module_Index_Grid extends Mage_Core_Adminhtml_Block_Widget_Grid
{
// ...
protected function _prepareCollection() {
$myCollection = Mage::getModel('my_module/model')->getCollection();
$this->setCollection($myCollection);
parent::_prepareCollection();
}
// ...
protected function _afterLoadCollection() {
usort($this->_collection, array($this, '_natSortCollection'));
return parent::_afterLoadCollection();
}
protected function _natSortCollection($a, $b) {
return strnatcmp($a->getField(), $b->getField());
}
}
Edit
See the updated code below to do what you want.
protected function _afterLoadCollection()
{
$items = $this->_collection->getItems();
/* To prevent duplicate items, and to not reload from the database
we have to remove each item individually without "clear()"ing
the collection. */
array_walk(array_keys($items), array($this->_collection, 'removeItemByKey'));
usort($items, array($this, '_natSortCollection'));
/* Now add each item back to the collection in the new order */
array_walk($items, array($this->_collection, 'addItem'));
return parent::_afterLoadCollection();
}
protected function _natSortCollection($itemA, $itemB)
{
return strnatcmp($itemA->getName(), $itemB->getName());
}
-
Thanks for the answer! Your example code is for a custom module. What changes are needed so that I could put it straight in the: \core\Mage\Adminhtml\Block\Widget\Grid.php ? Commented Mar 21, 2017 at 12:16
-
1The above code was only meant to guide you, not be a full-fledged working example. I would never suggest you overwrite the core files, even temporarily for testing purposes. For the
Mage/Adminhtml/Block/Catalog/Product/Grid.php
file, you should only have to add the_afterLoadCollection
and_natSortCollection
methods. Without knowing the error you're running in to, I won't be able to help much– BrettCommented Mar 21, 2017 at 12:49 -
1The core grid already has the
_prepareCollection
method so you don't need to add that. The_afterLoadCollection
should be being called automatically. I would check the parent of the grid and make sure there is a reference to a call to_afterLoadCollection
in it; otherwise, it won't work (but the feature exists in 1.9).– BrettCommented Mar 23, 2017 at 1:59 -
1Just downloaded Magento 1.7.0.2.
Mage/Adminhtml/Block/Catalog/Product/Grid
extendsMage/Adminhtml/Block/Widget/Grid
. The_prepareCollection
method callsparent::_prepareCollection
at the end which will call_afterLoadCollection
. If you add the_afterLoadCollection
method to theMage/Adminhtml/Block/Catalog/Product/Grid
it should execute. My guess here is that the collection is ignoring the reordering of items. Instead, you may need to create a newVarien_Data_Collection
and manually add the items in the order you want.– BrettCommented Mar 23, 2017 at 20:29 -
1So I just edited my post with another code snippet that works in Magento 1.9 and should work in Magento 1.7. Hope it helps.– BrettCommented Mar 23, 2017 at 20:51
From your comments in the previous answer, it may behoove you to use the MySQL SOUNDEX(<column_name>)
function to naturally sort your data. You can even then add a LENGTH(<column_name>)
call and finally <column_name>
. For example:
$this->getCollection()->addWebsiteNamesToResult();
$this->getCollection()->getSelect()->reset(Zend_Db_Select::ORDER);
$this->getCollection()->getSelect()->order(new Zend_Db_Expr(
sprintf(
'SOUNDEX(%1$s) %2$s, LENGTH(%1$s) %2$s, %1$s %2$s',
$this->getParam($this->getVarNameSort(), $this->_defaultSort),
$this->getParam($this->getVarNameDir(), $this->_defaultDir)
)
));
This isn't perfect, but there isn't "natural sorting" in MySQL. So it's kind of as close as you can get to it. Using a separate method to alter the collection would add a layer of complexity and require work-arounds to make changing the sort column and direction to work 100% of the time.
This is just an alternative to the custom sort method above.
-
Hmm, either I'm implementing it wrong or it doesn't seem to be working, although I admit that I was not able to fully wrap my head around how the SOUNDEX and LENGHT together would create something similar to natsort. Currently I'm placing the code at the very end of
_prepareCollection()
right after the$this->getCollection()->addWebsiteNamesToResult();
that was already there. Commented Mar 24, 2017 at 9:56 -
That's where I had that code and it worked for me. Basically
SOUNDEX()
orders it alphabetically, then theLENGTH()
is there to help with things with numbers after them (e.g. "Random String 1", "Random String 2", "Random String 11") and finally it sorts it as it normally would. So instead of getting "Random String 1", "Random String 11", "Random String 2", you get a properly ordered list.– BrettCommented Mar 24, 2017 at 12:57 -
Really odd, I must be doing something wrong then... Is this how it is supposed to look like link ? just to be sure- this is the only edit needed for this method to work, right? Commented Mar 24, 2017 at 20:34
-
Yeah, that should be all that's necessary. It's what I did and it worked.– BrettCommented Mar 25, 2017 at 0:08
-
Is it possible that I am missing something in the
Zend_Db_Expr
? Commented Mar 25, 2017 at 8:41