Issue with a model with a many to many relationship involved
  • toymachiner62toymachiner62 February 11
    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);
    }
    }



  • toymachiner62toymachiner62 February 11
    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 = '';
    }
  • adminadmin February 11
    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?
  • toymachiner62toymachiner62 February 12
    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.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In Apply for Membership

Categories