Issue with a model with a many to many relationship involved

I have a photos module and a categories module created and I want a user to be able to add a photo via the photos module and select a category to go along with that photo.

I've got most of it working except when I click save on the photos module, i get an error saying "Message: Undefined index: photo_category_id"

Sorry for the long post, but I wasn't sure what you'd need.

Here's my database tables:
CREATE TABLE `photos` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `title` varchar(255) DEFAULT NULL, `filename` varchar(255) NOT NULL DEFAULT '', `published` enum('yes','no') DEFAULT 'yes', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=latin1; CREATE TABLE `photo_categories` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `title` varchar(255) DEFAULT NULL, `filename` varchar(255) NOT NULL DEFAULT '', `published` enum('yes','no') DEFAULT 'yes', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1; CREATE TABLE `categories_to_photos` ( `category_id` int(11) unsigned NOT NULL, `photo_id` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`category_id`,`photo_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Here's my Photos module:
<?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('category_id' => $data)); } // 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 12:23PM
    Here's my photo_categories_module
    <?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('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); } }

    Here's my Photos_to_categories module
    <?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.category_id = photo_categories.id', 'left'); } } class Category_to_photo_model extends Data_record { public $category_name = ''; public $title = ''; }
  • edited 12:23PM
    I think this may have something to do with this line in the Photos model form_fields method and how MY_Model processes in in the parent::form_fields:
    $related = array('photo_categories' => 'categories_to_photos_model');
    What if you change the column name from "category_id" to "photo_category_id" in the "categories_to_photos" table?
  • edited 12:23PM
    That threw an exception but it was because i had to change places in my code to reference the new column name. Seems to work now.

    I think i see why that column should be called photo_category_id. it's because my categories table is called photo_categories.

    Thanks for your help on this one.
Sign In or Register to comment.