Jump to:

7940 Posts in 1543 Topics by 946 members

DataObjectManager Module

SilverStripe Forums » DataObjectManager Module » Uploading files from the front end

Discuss the DataObjectManager module, and the related ImageGallery module.

Moderators: martimiz, UncleCheese, Sean, biapar, Willr, Ingo, swaiba, simon_w

Page: 1
Go to End
Author Topic: 2673 Views
  • davepolyester
    Avatar
    Community Member
    47 Posts

    Uploading files from the front end Link to this post

    Hi team,

    Using a combination of Peter Bacon Darwin's Associated Folder module and a useful bit of code from Uncle Cheese, I've built a nice wee Resources page that allows FileDataObjects to be uploaded along with a Title and Description (using Uploadify) and displayed in a table for people to download. All is working fine.

    Can anyone show me how I can enable users to upload new Resources from the front end as well as through the CMS?

    Here's my ResourcesPage.php:

    <?php
    class ResourcePage extends Page
    {

        static $db = array(
          'PageHeading' => 'Varchar(200)',
          
    );
       
       static $has_many = array (
          'Resources' => 'Resource'
       );
       
        static $icon = "themes/tdg/images/treeicons/bricks";
       
       
       public function getCMSFields()
       {
          $f = parent::getCMSFields();
          
          $manager = new FileDataObjectManager(
             $this, // Controller
             'Resources', // Source name
             'Resource', // Source class
             'Attachment', // File name on DataObject
             array(
                'Name' => 'Name',
                'Description' => 'Description',
                'Category' => 'Category'
             ), // Headings
             'getCMSFields_forPopup' // Detail fields (function name or FieldSet object)
             // Filter clause
             // Sort clause
             // Join clause
          );
          
          /*$manager->setUploadFolder('assets/', $this->AssociatedFolder);*/
          
          $manager->setUploadFolder(str_replace('assets/','',$this->AssociatedFolder()->Filename));
             
          $manager->allowUploadFolderSelection();
          
          $manager->setFilter(
             'Category', // Name of field to filter
             'Filter by Category', // Label for filter
             singleton('Resource')->dbObject('Category')->enumValues() // Map for filter (could be $dataObject->toDropdownMap(), e.g.)
          );
          
          // If undefined, all types are allowed. Pass with or without a leading "."      
          $manager->setAllowedFileTypes(array());
          
          // Label for the upload button in the popup
          $manager->setBrowseButtonText("Upload");
          
          // In grid view, what field will appear underneath the icon. If left out, it defaults to the file title.
          $manager->setGridLabelField('Name');
          
          // Plural form of the objects being managed. Used on the "Add" button.
          // If left out, this defaults to [MyObjectName]s
          $manager->setPluralTitle('Resources');
                
          $f->addFieldToTab("Root.Content.Resources", $manager);
          $f->addFieldToTab('Root.Content.Main', new TextField('PageHeading', 'Page Heading Text'), 'Content');

          return $f;
       }

    }

    Object::add_extension('ResourcePage', 'AssociatedFolderDecorator');

    class ResourcePage_Controller extends Page_Controller
    {
             
    }
    ?>

    Here's the html from my page template that displays the Resources:

    <table class="resourceTable">
       <tr>
          <th class="resourceName">File Name</th>
          <th class="resourceDesc">Description</th>
    <th class="resourceCat">Category</th>
          <th class="resourceType">File Type</th>
    <th class="resourceSize">File Size</th>
       </tr>
                      <% control Resources %>            
       <tr>
          <td>
             <a href="$Attachment.URL">$Name</a>
    </td>
    <td>
                            $Description
    </td>
    <td>
       $Category
    </td>
    <td>
       $Attachment.FileType
    </td>
    <td>
       $Attachment.Size
    </td>
    </tr>

                <% end_control %>
    </table>

    Let me know if it would be useful to give you the Resource.php code (for the Resource DataObject).

    Many thanks,

    David

  • UncleCheese
    Avatar
    4085 Posts

    Re: Uploading files from the front end Link to this post

    This should get you started.

    http://www.leftandmain.com/silverstripe-screencasts/2010/08/25/uploadify-tutorial-part-2-working-with-frontend-forms/

    ---------------
    Silverstripe tips, tutorials, screencasts, and more. http://www.leftandmain.com

  • davepolyester
    Avatar
    Community Member
    47 Posts

    Re: Uploading files from the front end Link to this post

    Hi UC,

    Thanks for the suggestion. I'd already worked through the associated tutorial and tried to implement the code with no success. I've now downloaded your original code and copied that into mine to see if I could get it working, again to no avail. When I try to rebuild the database it just stalls when it gets to my ResourcePage.

    I'm a designer rather than a programmer so this is a little over my head, but here are some thoughts:

    My ResourcePage has_many Resources and the Resource Data Object has_one Attachment and ResourcePage. By comparison, both your JobApplication data object and JobApplicationPage have has_one Resume and has_many Recommendations. I don't see a stated relationship between your Page and your Data Object?
    Does this mean the SaveInto function won't work for me because I don't have an exact match between my form fields and the database fields and relationships in my Data Object?

    Also, my DataObject includes a getCMSfields_forPopup function. I'd love to be able to simply call that Popup rather than use a form on the page to add a new Resource DataObject to the page, if that makes sense.

    Here's my new ResourcePage.php code:

    <?php
    class ResourcePage extends Page
    {

        static $db = array(
          'PageHeading' => 'Varchar(200)'
          
    );
       
       static $has_many = array (
          'Resources' => 'Resource'
       );
       
        static $icon = "themes/tdg/images/treeicons/bricks";
       
       
       public function getCMSFields()
       {
          $f = parent::getCMSFields();
          
          $manager = new FileDataObjectManager(
             $this, // Controller
             'Resources', // Source name
             'Resource', // Source class
             'Attachment', // File name on DataObject
             array(
                'Name' => 'Name',
                'Description' => 'Description',
                'Category' => 'Category'
             ), // Headings
             'getCMSFields_forPopup' // Detail fields (function name or FieldSet object)
             // Filter clause
             // Sort clause
             // Join clause
          );
          
          /*$manager->setUploadFolder('assets/', $this->AssociatedFolder);*/
          
          $manager->setUploadFolder(str_replace('assets/','',$this->AssociatedFolder()->Filename));
             
          $manager->allowUploadFolderSelection();
          
          $manager->setFilter(
             'Category', // Name of field to filter
             'Filter by Category', // Label for filter
             singleton('Resource')->dbObject('Category')->enumValues() // Map for filter (could be $dataObject->toDropdownMap(), e.g.)
          );
          
          // If undefined, all types are allowed. Pass with or without a leading "."      
          $manager->setAllowedFileTypes(array());
          
          // Label for the upload button in the popup
          $manager->setBrowseButtonText("Upload");
          
          // In grid view, what field will appear underneath the icon. If left out, it defaults to the file title.
          $manager->setGridLabelField('Name');
          
          // Plural form of the objects being managed. Used on the "Add" button.
          // If left out, this defaults to [MyObjectName]s
          $manager->setPluralTitle('Resources');
                
          $f->addFieldToTab("Root.Content.Resources", $manager);
          $f->addFieldToTab('Root.Content.Main', new TextField('PageHeading', 'Page Heading Text'), 'Content');

          return $f;
       }

    }

    Object::add_extension('ResourcePage', 'AssociatedFolderDecorator');

    class ResourcePage_Controller extends Page_Controller
    {

    public function UploadForm() {
          $form = new Form (
             $this,
             "UploadForm",
             new FieldSet (
                new TextField('Name', _t('Resource.NAME','Name')),
                new TextField('Description', _t('Resource.DESCRIPTION','Description')),
                new DropdownField('Category', _t('Resource.CATEGORY','Category'), singleton('Resource')->dbObject('Category')->enumValues()),
                $resourcefile = new FileUploadField('Resources', _t('Resource.ATTACHMENT','Upload a new file')),            
                //$files = new MultipleFileUploadField('File', _t('Resource.ATTACHMENT','Upload several files to this page'))
             ),
             new FieldSet (
                new FormAction('doUpload', _t('Resource.UPLOAD','Upload'))
             ),
             new RequiredFields('Name','Description','Category','File')
          );
          
          $resourcefile->setUploadFolder(str_replace('assets/','',$this->AssociatedFolder()->Filename));
          
          $resourcefile->allowUploadFolderSelection();
          
          /*$file->setFileTypes(array(
             'pdf',
             'doc'
             'docx',
             'xls',
             'xlsx',
          
          ));
          
    /*
          $recommendations->uploadOnSubmit();
          $resume->uploadOnSubmit();
    */
          
          return $form;

       }
       
       public function doUpload($data, $form) {
          $form->saveInto($fileupload = new Resource());
          $fileupload->write();
          return array (
             'FileUpload' => $fileupload
          );

       }
             
    }
    ?>

    Here's my Resource.php Data Object:

    <?php
    class Resource extends DataObject
    {
       static $db = array (
          'Name' => 'Text',
          'Description' => 'Text',
          'Category' => "Enum('Data, Drafts, Drawings, Reports, Other')"
       );
       
       static $has_one = array (
          'Attachment' => 'File',
          'ResourcePage' => 'ResourcePage'
       );
       
       public function getCMSFields_forPopup()
       {
          return new FieldSet(
             new TextField('Name'),
             new TextareaField('Description'),
             new DropdownField('Category','Category', singleton('Resource')->dbObject('Category')->enumValues()),
             new FileIFrameField('Attachment')
          );
       }
    }
    ?>

    Thanks again for your help.

  • davepolyester
    Avatar
    Community Member
    47 Posts

    Re: Uploading files from the front end Link to this post

    Righto, further progress with this:

    I've called getFrontendFields so the following code is pulling the fields from the DataObject into the Front End for me.

    public function UploadForm(){
    $fields = singleton('Resource')->getFrontendFields();
    $actions = new FieldSet(
    new FormAction('doUpload', 'Upload Resource')
    );
       
        $fields->removeByName('Associated Folder');

    $validator = NULL;
    $form = new Form(
    $this,
    'UploadForm',
    $fields,
    $actions,
    $validator
    );
       
    return $form;

    }

    public function doUpload($data, $form) {
          $form->saveInto($fileupload = new Resource());
          $fileupload->write();
          return array (
             'FileUpload' => $fileupload
          );

       }

    This is working apart from one thing: The file is being uploaded to the default Uploads folder, not the Associated Folder that is linked with the page.

    I've tried to include the following code to set the correct upload folder but it throws a "method does not exist on this class" error no matter where I put it:

    $fields->setUploadFolder(str_replace('assets/','',$this->AssociatedFolder()->Filename));

    Any suggestions of another method I can use to set the correct upload folder?

  • UncleCheese
    Avatar
    4085 Posts

    Re: Uploading files from the front end Link to this post

    You need to run that method on an FileUploadField object. You're trying to run it on a FieldSet.

    --------------------
    SilverStripe tips, tutorials, screencasts and more: http://www.leftandmain.com

  • davepolyester
    Avatar
    Community Member
    47 Posts

    Re: Uploading files from the front end Link to this post

    Thanks UC, yes I figured that out but wasn't able to work out how to turn the appropriate FrontendField into a FileUploadField in order to be able to apply the method.

    However, after much hair pulling I've finally got something working... almost! Basically, I've created the FileUploadField within the function, then used a replaceField method to replace the file field from my Resource data object with the new FileUploadField. (Hope I've explained that right.)

    The end result is that a new FileDataObject is created and appears in my table, and the file itself is uploaded to the correct folder associated with the page. However, three problems remain:

    Firstly, I can click the browse button of the Uploadify field and select a file but when I click the Open button in the dialogue box, the subsequent upload does not appear in the Uploadify field. It still just shows the 'No file uploaded' text, even though the file is uploading correctly.

    Secondly, when I check in the CMS to see if my file has uploaded correctly, the file appears in the correct folder but the link to this file appears to be broken in the DataObjectManager.
    When I check the download link in the table on my page, the path to the file simply says '...assets/' whereas the correct path should be '...assets/associated-folders/thisAssociatedFolder/thisFileName.pdf'.

    Thirdly, I'd like to use the UploadOnSubmit method too, as described in your tutorial, but when I try it the file isn't uploaded at all.

    Hopefully you can point me to some solutions! Thanks again for lending me your genius!

    Here's my code:

    public function UploadForm(){
    $fields = singleton('Resource')->getFrontendFields();
    $actions = new FieldSet(
           new FormAction('doUpload', 'Upload Resource')
    );
       
       $resourcefile = new FileUploadField('Resources', _t('Resource.ATTACHMENT','Upload a new file'));
       
       $resourcefile->setUploadFolder(str_replace('assets/','',$this->AssociatedFolder()->Filename));
       //$resourcefile->uploadOnSubmit();
       
       $fields->removeByName('Associated Folder');
       $fields->replaceField('Attachment', $resourcefile);

    $validator = NULL;
    $form = new Form(
    $this,
    'UploadForm',
    $fields,
    $actions,
    $validator
    );
       
    return $form;

    }

    public function doUpload($data, $form) {
          $form->saveInto($fileupload = new Resource());
          $fileupload->write();
          return array (
             'FileUpload' => $fileupload
          );

       }

  • davepolyester
    Avatar
    Community Member
    47 Posts

    Re: Uploading files from the front end Link to this post

    Hi UC and community,

    Hoping I can get some more input on this issue.

    Have just bought a new Mac (with Lion) and for some reason the Uploadify browse button is all of a sudden not functioning at all in Firefox (6.0.1) or Safari (5.1) but still working fine in Chrome, go figure. No changes made to my code at all!

    All of the problems in my previous post still apply.

    Thanks team.

    2673 Views
Page: 1
Go to Top

Want to know more about the company that brought you SilverStripe? Then check out SilverStripe.com

Comments on this website? Please give feedback.