2

I am trying to build a component called com_usedbooks with a module called mod_usedsearch. The user can view books by clicking a Menu Item called 'Used Books' (/used-books) which will show a paginated list or by searching it using a module from any page where they can filter it by author and author.

I got the List View working but when I search with the module, I have two problems which I think are interrelated:

When the search form in the module is submitted, it seems to be getting submitted to current component context. So if I am submitting the Search Form from the root URL, I get a different query string (/?genre=fiction&author=all&option=com_usedbooks&view=search&Itemid=101) compared to when I submit the Search Form in the Used Books List page (/used-books?genre=fiction&author=all&option=com_usedbooks&view=search&Itemid=108).

In both cases, the list page with the correct filtered data is displayed but with one catch and that is when I click on Page 2 on the pagination links, it goes to: /used-books/fiction/0?author=all&start=5.

My guess is that the problem lies in the router but I am struggling to find what it is. What I am trying to do is when the search form is submitted from any component context, it will be have a query string like /used-books/search/?genre=fiction&author=all and similarly for the pagination to be /used-books/search/?genre=fiction&author=all&limit=5 and so on.

I am not sure what I would put on the case 'search' to achieve what I want.

I have referenced the relevant bits of code below:

<!-- Module Search Form -->
<form name="books-search" action="<?php echo JRoute::_('index.php')?>" method="get">
<!-- fields -->
<input type="hidden" name="option" value="com_usedbooks">
<input type="hidden" name="view" value="search">


<?php
/* Model
 * /com_usedbooks/models/search.php 
*/

class UsedbooksModelSearch extends JModelList {

    protected function getListQuery() {
        $db = JFactory::getDBO();
        $query = $db->getQuery(true);

        // Get the genre
        $genre = $this->getState('genre', '');

        $query
            ->select('*')
            ->from($db->quoteName('used_books'))
            ->where('genre = ' . $db->quote($genre))
            ->order('id ASC');

        return $query;
    }

    protected function populateState ($ordering = null, $direction = null) {
        $app = JFactory::getApplication();

        $this->setState('genre', $app->input->get('genre', '', 'STRING'));

        // Limit the number of list items per page
        $this->setState('list.limit', $app->input->get('limit', 5, 'uint'));

        /* Sets the offset where the page should start, for e.g
         * Page limitstart=5 will start the list with the 6th item
        */
        $this->setState('list.start', $app->input->get('limitstart', 0, 'uint'));
    }
}

/* View
 * /com_usedbooks/views/search/tmpl/default.php 
*/
class UsedbooksViewSearch extends JViewLegacy
{
    // Overwriting JView display method
    function display($tpl = null)
    {
        // Get the Used Books Array
        $this->items = $this->get('Items');

        // Pagination
        $this->pagination = $this->get('Pagination');

        // Display the view
        parent::display($tpl);
    }
}
?>

<!-- /com_usedbooks/views/search/tmpl/default.php -->
<form action="<?php echo htmlspecialchars(JFactory::getURI()->toString()); ?>" method="get">
    <?php foreach ($usedBooks as $usedBook): ?>
        <h2><?php echo $usedBook->title . ' - '. $usedBook->author; ?></h2> 
    <?php endforeach; ?>

    <?php echo $this->pagination->getListFooter(); ?>
    <?php echo $this->pagination->getLimitBox(); ?>
    <?php echo $this->pagination->getResultsCounter(); ?>
</form>

<?php
/* Router
 * /com_usedbooks/router.php 
*/
function UsedbooksBuildRoute(&$query)
{
    $segments = array();

    if(isset($query['genre'])){
        $segments[] = $query['genre'];
        unset($query['genre']);
    }

    if(isset($query['author'])){
        $segments[] = $query['author'];
        unset($query['author']);
    }

    if(isset($query['id'])){
        $segments[] = $query['id'];
        unset($query['id']);
    }
    unset( $query['view'] );

    return $segments;
}

function UsedbooksParseRoute($segments)
{
    $vars = array();
    $app =& JFactory::getApplication();
    $menu =& $app->getMenu();
    $item =& $menu->getActive();

    // Count segments
    $count = count($segments);

    //Handle View and Identifier
    switch($item->query['view'])
    {
    case 'usedbooks':
        if($count == 1) {
            $vars['view'] = 'genre';
        }
        if($count == 2) {
            $vars['view'] = 'author';
        }
        if($count == 3) {
            $vars['view'] = 'usedbook';
        }
        $id = explode( ':', $segments[$count-1] );
        $vars['id'] = (int) $id[0];

        break;

    case 'genre':
        if($count == 1) {
            $vars['view'] = 'genre';
        }
        if($count == 2) {
            $vars['view'] = 'author';
        }
        $id = explode(':', $segments[$count-1]);
        $vars['id'] = (int) $id[0];
        break;

    case 'author':
        if($count == 1) {
            $vars['view'] = 'author';
        }
        if($count == 2) {
            $vars['view'] = 'usedbook';
        }
        $id = explode(':', $segments[$count-1]);
        $vars['id'] = (int) $id[0];
        break;

    case 'usedbook':
        $reg = explode(':', $segments[$count-1]);
        $vars['reg'] = (int) $reg[0];
        $vars['view'] = 'usedbook';
        break;

    case 'search':

        break;
    }
    return $vars;
}
4
  • Did you add your start and length pagination URL params to your component level controller's $safeurlparams variable before calling parent class display method? Also, did you add the existing filters (author, genre) which built the result set; into the search results form so when pagination request fires they're available to the model? Commented Nov 24, 2014 at 21:48
  • Hi Brian, not sure if I 'understood' your questions correctly as I am just starting to learn the workings of Joomla's MVC in the component but let me try.
    – sifu
    Commented Nov 25, 2014 at 0:38
  • Pressed enter by mistake, and had not idea could edit for only 5 minutes. Here is the remaining part of the reply: 1. I have set the start/length pagination URL params (limitstart and start on the two models (/models/search.php and /models/usedcars.php) in populateState method. 2. And the existing filters are available to the model as I have used the following code on the action: <form action="<?php echo htmlspecialchars(JFactory::getURI()->toString()); ?>" method="get">
    – sifu
    Commented Nov 25, 2014 at 0:56
  • Saw one item which will resolve the two different urls at least, you wouldn't happen to have a Dev site where I could see live the pagination issues.? Commented Nov 25, 2014 at 1:13

1 Answer 1

3

I think I see the issue with the search module form destination url. The form action attribute needs the option and view parameters. I see you added them as hidden field at the end of the form, but try removing those fields and adding to the JRoute url like so:

<form name="books-search" action="<?php echo JRoute::_('index.php?option=com_usedbooks&view=search')?>" method="get">

Since these are crucial for the frame work properly routing the request, this should at least ensure the module form routes to the proper component and view.

2
  • Ha I was writing a reply to say I have solved the issue (with a lot of help from hple in the Joomla IRC). And you are absolutely correct that the issue was indeed the form action attribute JRoute::_('index.php') was the cause as the action was simply 'appending' to the menu item (hence /?genre=fiction in root and /used-books?genre=fiction when the module was submitted from used-books link). I simply added a module param to select the menu item ID and then used it like this on the form and this did the trick. JRoute::_('index.php?Itemid=' . $itemid . '&view=search')
    – sifu
    Commented Nov 25, 2014 at 1:23
  • Sweeeeet, glad you got it working! Commented Nov 25, 2014 at 1:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.