I'm trying to figure out how to handle a file upload in a module with related modules

edited February 2012 in Bug Reports
What i'm trying to do is create a photos module where users can upload photos. Each uploaded photo can have multiple categories so when the public views the site, they will see a photos page with all the categories and then click a category and it shows all the photos.

Currently I have a photo_categories module which allows users to create a category and upload a photo. This photo will be the one that is displayed along with the category name. I also have a photos module which allows users to upload photos and select multiple categories for the photo their uploading.

The problem is that when on the photos module, there is a button next to the categories to add a new category. When you click the add button, from what I can tell it's pulling in the photo_categories module in a modal box. I enter a title and click the upload button to choose a file and click save and the title gets to the db, but the file never gets uploaded. This seems strange to me because if I go directly to the photo_categories module, the file upload is handled just fine.

Why would the file upload get handled directly in the photo_categories module, but not when it's in a modal window in the photos module?

Photos_model:
<?php if (!defined('BASEPATH')) exit('No direct script access allowed'); class Photos_model extends Base_module_model { function __construct() { parent::__construct('photos'); } // method used to list the data in the admin panel function list_items($limit = NULL, $offset = NULL, $col = 'id', $order = 'asc') { // the data to list //$this->db->select('id, title, filename, published', FALSE); $data = parent::list_items($limit, $offset, $col, $order); return $data; } // used to return form information to the form builder class to render the create/edit screens in the admin panel function form_fields($values = array()) { $related = array('photo_categories' => 'categories_to_photos_model'); $fields = parent::form_fields($values, $related); // to limit the image folder to just the projects folder for selection $fields['image']['class'] = 'asset_select images/uploads/photos'; $upload_path = assets_server_path('uploads/photos', 'images'); $fields['filename'] = array('type' => 'file', 'upload_path' => $upload_path, 'overwrite' => TRUE, 'required' => TRUE); // fix the preview by adding galleryImages in front of the image path since we are saving it in a subfolder if (!empty($values['filename'])) { $fields['filename']['before_html'] = '<div class="img_display"><img src="'.img_path('uploads/photos/thumbs/'.$this->thumb_name($values['filename'])).'" style="float: right;"/></div>'; } // remove that extra image upload field that always appears unset($fields['image']); $CI =& get_instance(); $CI->load->model('photo_categories_model'); //$CI->load->model('categories_model'); $CI->load->model('categories_to_photos_model'); //$category_options = $CI->photo_categories_model->options_list('id', 'title', array('published' => 'yes')); //$fields['category_id'] = array('type' => 'select', 'options' => $category_options); return $fields; } // saves the data in the categories_to_photos table. Basically saves the link between the photos and the categories function on_after_save($values) { $data = (!empty($this->normalized_save_data['photo_categories'])) ? $this->normalized_save_data['photo_categories'] : array(); $this->save_related('categories_to_photos_model', array('photo_id' => $values['id']), array('photo_category_id' => $data)); //$this->on_after_post($values); } // creates a thumbnail of an image that is uploaded function on_after_post($values) { $CI =& get_instance(); $CI->load->library('image_lib'); // create the thumbnail if an image is uploaded if (!empty($CI->upload)) { $data = $CI->upload->data(); if (!empty($data['full_path'])) { $thumb_img = assets_server_path('uploads/photos/thumbs/'.$this->thumb_name($data['file_name']), 'images'); // resize to proper dimensions $config = array(); $config['source_image'] = $data['full_path']; $config['create_thumb'] = FALSE; //$config['new_image'] = $thumb_img; $config['width'] = 1024; $config['height'] = 768; $config['master_dim'] = 'auto'; $config['maintain_ratio'] = FALSE; $CI->image_lib->clear(); $CI->image_lib->initialize($config); if (!$CI->image_lib->resize()) { $this->add_error($CI->image_lib->display_errors()); } // create thumb $config = array(); $config['source_image'] = $data['full_path']; $config['create_thumb'] = FALSE; $config['new_image'] = $thumb_img; $config['width'] = 185; $config['height'] = 120; $config['master_dim'] = 'auto'; $config['maintain_ratio'] = TRUE; $CI->image_lib->clear(); $CI->image_lib->initialize($config); if (!$CI->image_lib->resize()) { $this->add_error($CI->image_lib->display_errors()); } } } return $values; } // actually delete the images from the folder when a user delete's them function on_before_delete($where) { $id = $this->_determine_key_field_value($where); $data = $this->find_by_key($id); $files[] = assets_server_path('uploads/photos/'.$data->filename, 'images'); // finds the actual image $files[] = assets_server_path('uploads/photos/thumbs/'.$this->thumb_name($data->filename), 'images'); // finds the thumbnail foreach($files as $file) { if (file_exists($file)) { @unlink($file); } } } // gets the thumbnail image name function thumb_name($image) { return preg_replace('#(.+)(\.jpg|\.png)#U', '$1_thumb$2', $image); } } class Photo_model extends Base_module_record { /*public function get_gallery_image() { return '<img src="'.img_path($this->path).'" />'; }*/ function get_image_path() { return img_path('uploads/photos/'.$this->filename, NULL, TRUE); } function get_thumb() { $thumb = $this->_parent_model->thumb_name($this->filename); return img_path('uploads/photos/thumbs/'.$thumb); } }

Comments

  • edited February 2012
    Photo_categories model:

    <?php if (!defined('BASEPATH')) exit('No direct script access allowed'); class Photo_categories_model extends Base_module_model { public $record_class = 'Photo_category'; function __construct() { parent::__construct('photo_categories'); } // method used to list the data in the admin panel function list_items($limit = NULL, $offset = NULL, $col = 'id', $order = 'asc') { // the data to list //$this->db->select('id, title, filename, published', FALSE); $data = parent::list_items($limit, $offset, $col, $order); return $data; } // used to return form information to the form builder class to render the create/edit screens in the admin panel function form_fields($values = array()) { $fields = parent::form_fields($values); // to limit the image folder to just the projects folder for selection $fields['image']['class'] = 'asset_select images/uploads/photo_categories'; $upload_path = assets_server_path('uploads/photo_categories', 'images'); $fields['filename'] = array('type' => 'file', 'upload_path' => $upload_path, 'overwrite' => TRUE, 'required' => TRUE); // fix the preview by adding galleryImages in front of the image path since we are saving it in a subfolder if (!empty($values['filename'])) { $fields['filename']['before_html'] = '<div class="img_display"><img src="'.img_path('uploads/photo_categories/thumbs/'.$this->thumb_name($values['filename'])).'" style="float: right;"/></div>'; } // remove that extra image upload field that always appears unset($fields['image']); return $fields; } // creates a thumbnail of an image that is uploaded function on_after_post($values) { $CI =& get_instance(); $CI->load->library('image_lib'); // create the thumbnail if an image is uploaded if (!empty($CI->upload)) { $data = $CI->upload->data(); if (!empty($data['full_path'])) { $thumb_img = assets_server_path('uploads/photo_categories/thumbs/'.$this->thumb_name($data['file_name']), 'images'); // resize to proper dimensions $config = array(); $config['source_image'] = $data['full_path']; $config['create_thumb'] = FALSE; //$config['new_image'] = $thumb_img; $config['width'] = 1024; $config['height'] = 768; $config['master_dim'] = 'auto'; $config['maintain_ratio'] = FALSE; $CI->image_lib->clear(); $CI->image_lib->initialize($config); if (!$CI->image_lib->resize()) { $this->add_error($CI->image_lib->display_errors()); } // create thumb $config = array(); $config['source_image'] = $data['full_path']; $config['create_thumb'] = FALSE; $config['new_image'] = $thumb_img; $config['width'] = 185; $config['height'] = 120; $config['master_dim'] = 'auto'; $config['maintain_ratio'] = TRUE; $CI->image_lib->clear(); $CI->image_lib->initialize($config); if (!$CI->image_lib->resize()) { $this->add_error($CI->image_lib->display_errors()); } } } return $values; } // actually delete the images from the folder when a user delete's them function on_before_delete($where) { $id = $this->_determine_key_field_value($where); $data = $this->find_by_key($id); $files[] = assets_server_path('uploads/photo_categories/'.$data->filename, 'images'); // finds the actual image $files[] = assets_server_path('uploads/photo_categories/thumbs/'.$this->thumb_name($data->filename), 'images'); // finds the thumbnail foreach($files as $file) { if (file_exists($file)) { @unlink($file); } } } // cleanup category to articles function on_after_delete($where) { $CI =& get_instance(); $CI->load->model('categories_to_photos_model'); if (is_array($where) && isset($where['id'])) { $where = array('photo_category_id' => $where['id']); $CI->categories_to_photos_model->delete($where); } } // gets the thumbnail image name function thumb_name($image) { return preg_replace('#(.+)(\.jpg|\.png)#U', '$1_thumb$2', $image); } } class Photo_category_model extends Base_module_record { /*public function get_gallery_image() { return '<img src="'.img_path($this->path).'" />'; }*/ function get_image_path() { return img_path('uploads/photo_categories/'.$this->filename, NULL, TRUE); } function get_thumb() { $thumb = $this->_parent_model->thumb_name($this->filename); return img_path('uploads/photo_categories/thumbs/'.$thumb); } }

    Categories_to_photos_model:
    <?php if (!defined('BASEPATH')) exit('No direct script access allowed'); class Categories_to_photos_model extends MY_Model { public $record_class = 'Category_to_photo'; function __construct() { parent::__construct('categories_to_photos'); } function _common_query() { $this->db->select('categories_to_photos.*, photos.title, photo_categories.title AS category_name, photos.published'); $this->db->join('photos', 'categories_to_photos.photo_id = photos.id', 'left'); $this->db->join('photo_categories', 'categories_to_photos.photo_category_id = photo_categories.id', 'left'); } } class Category_to_photo_model extends Data_record { public $category_name = ''; public $title = ''; }
  • If you know of a better way of handling this scenario i'm all ears.
  • edited 5:28AM
    Hmm... I'm not exactly sure what the issue is. I will say that editing a module's data inline involves ajaxing in content and calling a different method on the controller ("inline_edit" as opposed to the "edit" method on fuel/modules/fuel/controllers/module.php). I would start by seeing where the script gets in that module.php file in particular the _process_uploads method which is called around line 1152 in the inline_edit method.

    This will change in the next release so that it is essentially calling the same function in an iframe (instead of being ajaxed in) but realize stating that will not help out your current situation.
  • Thanks for pointing me in the right direction. So the file actually gets uploaded, but my filename field in the database does not get populated. I'm still trying to debug through module.php to see where it chokes.

    If you look at line 1150, you'll see this line:
    $saved_id = $this->model->save($posted);

    Can you tell me where this save method is coming from or what it's referring to? I'm not seeing a model called "model" in the /fuel/modules/fuel/models/ folder.
  • edited 5:28AM
    Sorry for the delay in response... I didn't see this last post. "model" is just the generic name we set (as the second parameter of $this->load->model('my_model', 'model')). For the file name to be pulled in, the field name should that has the file upload, should have "_upload" appended to the name. So if you have a text field of "my_file" to hold the file name, then you should have a field name of "my_file_upload".

    Also, there was an update yesterday to help with an issue if the file upload field name didn't have the "_upload" suffix and the file name that was uploaded would be lowercased whereas the field value that would be saved to the "my_file" field would not be.
  • edited 5:28AM
    If it helps, that save method is in /application/core/MY_Model around #938
Sign In or Register to comment.