1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

How to create export function so member can download a CSV file

Discussion in 'XenForo Development Discussions' started by AndyB, Dec 22, 2015.

  1. AndyB

    AndyB Well-Known Member

    Hello,

    I'm creating an add-on which I would like to add an 'export' function. The way I would like to make it work is to add the code to the ControllerPublic/NewsletterSubscribe.php file.

    For example the admin will invoke the export function by adding the the word export after the route.

    Example:

    http://www.domain.com/newslettersubscribe/export

    With this URL I would like my add-on to prepare the $results and have a download dialog box appear on the admins display where he can download the $results to his computer.

    Currently i have the following:

    library/Andy/NewsLetterSubscribe/ControllerPublic/NewletterSubscribe

    PHP:
        public function actionExport()
        {
            
    // get permission
            
    if (!XenForo_Visitor::getInstance()->hasPermission('newsletterSubscribeGID''newsletterSubscribeID'))
            {
                throw 
    $this->getNoPermissionResponseException();
            }
            
            
    // get database
            
    $db XenForo_Application::get('db');        
            
            
    // get data
            
    $results $db->fetchCol("
                SELECT email
                FROM xf_newsletter_subscribe
                ORDER BY email ASC
            "
    );
        }
    What code do I need to add?

    Thank you.
     
  2. Jake B.

    Jake B. Well-Known Member

    You separate the emails with commas. Also, you probably don't want to use fetchCol.

    implode()
     
  3. AndyB

    AndyB Well-Known Member

    Hi Jake B.,

    Thank you for your post. Yes I understand that part, sorry I wasn't more clear. The part I'm having trouble with is to get a prompt to save the file. I understand I will need to add some header code or call a function for this.
     
  4. Jake B.

    Jake B. Well-Known Member

  5. AndyB

    AndyB Well-Known Member

    I've tried that type of code and it doesn't work.

    I've already looked but was not able to figure out, hence my post for help.
     
  6. Jake B.

    Jake B. Well-Known Member

    Everything you'll need is in
    XenForo_ControllerPublic_Attachment::actionIndex
    and
    XenForo_ViewPublic_Attachmentview::renderRaw
     
  7. AndyB

    AndyB Well-Known Member

    My question is how to get a download dialog by adding code to the ControllerPublic, I'm not sure if it's possible. I was not able to use the code in other controllers, hence my call for help.
     
  8. Jake B.

    Jake B. Well-Known Member

    Yes, you'll need to use a view. Take a look at XenForo_ViewPublic_Attachmentview::renderRaw
     
  9. AndyB

    AndyB Well-Known Member

    Thank you for your suggestion.

    What code would I use in the library/Andy/NewsLetterSubscribe/ControllerPublic/NewletterSubscribe.php file to call the XenForo_ViewPublic_Attachment_View class?
     
  10. Jake B.

    Jake B. Well-Known Member

    You wouldn't call XenForo_ViewPublic_Attachment_View, you'd create your own view and use parts of the code from that.
     
  11. AndyB

    AndyB Well-Known Member

    How would I call that code? I would like to be ableto use the following URL to call the export function:

    http://www.domain.com/newslettersubscribe/export
     
  12. AndyB

    AndyB Well-Known Member

    I almost got this working perfect with this code:

    PHP:
        public function actionExport()
        {
            
    // get permission
            
    if (!XenForo_Visitor::getInstance()->hasPermission('newsletterSubscribeGID''newsletterSubscribeID'))
            {
                throw 
    $this->getNoPermissionResponseException();
            }

            
    // get database
            
    $db XenForo_Application::get('db');        
            
            
    // get data
            
    $results $db->fetchCol("
                SELECT email
                FROM xf_newsletter_subscribe
                ORDER BY email ASC
            "
    );    
            
            
    // define variable
            
    $csv '';
            
            foreach (
    $results as $result)
            {
                
    $csv $csv $result ',';
            }

            
    // write to temporary file
            
    $file tempnam(XenForo_Helper_File::getTempDir(), 'xf');
            
            
    $handle fopen($file"w");
            
    fwrite($handle$csv);
            
    fclose($handle);
            
            
    // rename file
            
    XenForo_Helper_File::safeRename($file'/tmp/export.csv');    
            
            
    // decalre variable
            
    $file '/tmp/export.csv';
            
            if (
    file_exists($file)) {
                
    header('Content-Description: File Transfer');
                
    header('Content-Type: application/octet-stream');
                
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
                
    header('Expires: 0');
                
    header('Cache-Control: must-revalidate');
                
    header('Pragma: public');
                
    header('Content-Length: ' filesize($file));
                
    readfile($file);
                exit();
            }        
        }
    The one problem is the code uses the exit() command, so after you save the export.csv file to your local disk, the URL changes internally to the web root:

    http://www.domain.com/

    So this is a little confusing and I'm not sure why this happens.
     
  13. AndyB

    AndyB Well-Known Member

    Got it.

    What I needed to do was to have the following link:

    http://www.domain.com/newslettersubscribe/export

    call a template and in the template have a link to the actual export.

    PHP:
        public function actionExport()
        {
            
    // send to template
            
    return $this->responseView('Andy_Trader_ViewPublic_Trader','andy_newslettersubscribe_export');
        }
        
        public function 
    actionExportLink()
        {
            
    // get permission
            
    if (!XenForo_Visitor::getInstance()->hasPermission('newsletterSubscribeGID''newsletterSubscribeID'))
            {
                throw 
    $this->getNoPermissionResponseException();
            }        

            
    // get database
            
    $db XenForo_Application::get('db');        
            
            
    // get data
            
    $results $db->fetchCol("
                SELECT email
                FROM xf_newsletter_subscribe
                ORDER BY email ASC
            "
    );    
            
            if (!empty(
    $results))
            {
                
    // comma separate results
                
    $csv implode($results',');
                
                
    // remove trailing comma
                
    $csv rtrim($csv',');        
        
                
    // write to temporary file
                
    $file tempnam(XenForo_Helper_File::getTempDir(), 'xf');
                
                
    $handle fopen($file"w");
                
    fwrite($handle$csv);
                
    fclose($handle);
                
                
    // rename file
                
    XenForo_Helper_File::safeRename($file'/tmp/export.csv');    
                
                
    // decalre variable
                
    $file '/tmp/export.csv';
                
                if (
    file_exists($file)) {
                    
    header('Content-Description: File Transfer');
                    
    header('Content-Type: application/octet-stream');
                    
    header('Content-Disposition: attachment; filename="'.basename($file).'"');
                    
    header('Expires: 0');
                    
    header('Cache-Control: must-revalidate');
                    
    header('Pragma: public');
                    
    header('Content-Length: ' filesize($file));
                    
    readfile($file);        
                    exit();
                }
            }
        }
     
    Last edited: Dec 22, 2015
  14. rellect

    rellect Well-Known Member

    As a suggestion, you should learn/understand the Model-View-Controller architecture. You code is entirely in the controller, which is bad practice.
     
    Jake B., Xon and Martok like this.
  15. Xon

    Xon Well-Known Member

    Also consider using the built-in php function fputcsv to ensure the output is formatted correctly. Especially as email addresses can have all sorts of stuff encoded into them.
     

Share This Page