5

I would like to export all selected items from the items-view of my component.

To do so I modified my view and inserted a new button to the

JToolBarHelper::custom('items.exportcsv', 'download', '', 'COM_BESTIA_EXPORT', true);

I also modified the controller:

/**
 * exportcsv function.
 * 
 * @access public
 * @return void
 */
public function exportcsv()
{

    $jinput                 =           JFactory::getApplication()->input;
    $ids                    =           $jinput->get('cid', '', 'array');
    $modelitems     =           $this->getModel();

    $array                  =           array();

    foreach($ids as $id)
    {
        $item                           =   $modelitems->getItem($id);      
        $array[$item->id]['itemid'] =   $item->itemid;
    }

    $csv                                    =       ArrayHelper::exportArrayToCSV($array, "items-report");
    $this->setRedirect('index.php?option=bestia&view=items', false);        

}       

Now I created a function in a helper function to create the download:

/**
 * exportArrayToCSV function.
 * 
 * @access public
 * @static
 * @param mixed $array
 * @return void
 */
public static function exportArrayToCSV($array, $filename, $delimiter=";")
{
    $config                         =   JFactory::getConfig();
    $tmppath                        =   $config->get('tmp_path');

    $keys                           =   array_keys($array);

    if(is_dir($tmppath))
    {
        $filename                   =   "$filename.csv";
        $filepath                   =   "$tmppath/$filename";
        $file                       =   new SplFileObject($filepath, 'w');

        $file->fputcsv(array_keys($array[$keys[0]]),$delimiter);

        foreach ($array as $fields) 
        {
            $file->fputcsv($fields,$delimiter);
        }

        if(file_exists($filepath))
        {   
            header ( 'Content-Description: File Transfer' );
            header ( 'Content-Type: application/force-download' );
            header ( 'Content-Type: application/octet-stream' );
            header ( 'Content-Disposition: attachment; filename=' . $filename ); 
            header ( 'Expires: 0' );
            header ( 'Cache-Control: must-revalidate' );
            header ( 'Pragma: public' );
            header ( 'Content-Length: ' . filesize ($filepath) );
            ob_clean(); 
            flush();
                readfile ($filepath);
                unlink($filepath); 
            exit();
        }
        else                            return false;   
    }
    else                                return false;       
}

This also works fine.

But I am facing a strange behaviour: If I download a CSV and change the filter after downloading in the search bar like this:

enter image description here

The file is downloaded again.

I think the problem is somewhere around here:

            ob_clean(); 
            flush();
                readfile ($filepath);
                unlink($filepath); 
            exit();

But I do not know how to solve it.

5
  • 1
    It seems somehow you are requesting for same task (items.exportcsv) again on change of your filter or submitting the same form you will need to check code where you handle the these filter onchange event. Feb 19, 2016 at 5:44
  • Hello... Yes, the exit(); in the download-code prevents joomla from reloading the site and clearing the task-value in the hidden field. Unfortunately I did not find out how to create a download with PHP without using die; or exit;
    – MyFault
    Feb 19, 2016 at 19:41
  • Provide me more information are you submitting a from on change of your filter (for example onchange="this.form.submit();" ) if so then you will need to change task before submitting the form. Feb 20, 2016 at 5:48
  • Hello, yes, I'm using this.form.submit - the question is: How can I change the task?
    – MyFault
    Feb 20, 2016 at 10:12
  • this.form.task = ''; You can simply go like this. Like this.form.inputName
    – Alexandr
    Jan 18, 2017 at 19:52

3 Answers 3

1

This is because each search form change triggers form submit

So you need to return "task" field to it's default value, wich is empty by default

function submitForm(){ this.form.submit(); jQuery('input[name="task"]').val("");  }
1

Check if you have hidden field named task if not then add following:

<input type="hidden" value="" name="task">

Then change its value by editing on change event as follows:

onchange="submitForm();"

Then add following small script:

<script>
  function submitForm(){
    this.form.task = 'subcontroller.csvDownloadTask';
    this.form.submit();
    this.form.task = '';
  }
</script>
0

Alexandr's solution is not longer working in Joomla 4, my approach is now by using webassets manager to include the script: (default.php)

...
$wa = $this->document->getWebAssetManager();
$wa->addInlineScript("
    jQuery(document).ready(function(){
        jQuery('#toolbar-download').on('click', function(e){
            const taskField = document.querySelectorAll('[name=\"task\"]');
            taskField[0].value = '';
        });
    });");
...

In the HtmlView.php adding the Button as follows:

...
ToolbarHelper::custom('seasons.export', 'download', '', 'COM_YOURCOMPONENT_BTN_LABEL_EXPORT', true);
...

Please note that #toolbar-download is the ID of your Export / Download Button.

seasons.export is the method that should be called in your controller:

SeasonsController.php

...
public function export()
    {
        $ids = $this->input->get('cid', [], 'array');
        error_log(print_r($ids, true));
        $model = $this->getModel('seasons');
        $data  = $model->exportItems($ids);
        $separator = ",";
        $enclosure = "\"";
        $escape = "\\";
        $eol   = "\n";
        $filename = 'seasons.csv';
        $headers  = array_keys($data[0]);
        $output   = fopen('php://output', 'wb');
        fputcsv($output, $headers, $separator, $enclosure, $escape, $eol);
        foreach ($data as $row)
        {
            fputcsv($output, $row);
        }

        header('Content-Type: text/csv');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        fclose($output);

        exit;
    }
...

That way the download works and when changing afterwards the filter it won't trigger the download again.

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.