views:

110

answers:

2

Hi. I'm trying to build my first app on CodeIgniter. This is also my first time trying to stick to OOP and MVC as much as possible. It's been going ok so far but now that I'm trying to write my first model I'm having some troubles. Here's the error I'm getting:

A Database Error Occurred

Error Number: 1064

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Castledine' at line 3

SELECT * FROM (authors) WHERE author = Earle Castledine

Which, as you'll see below, relates to the following line in my model:

$this->db->get_where('authors', array('author' => $author));

I'm not quite sure why it's throwing the error. Is it because Earle Castledine isn't in quotes? If so, why doesn't CI put them in there? I would doubt that's the issue, rather to think it's my fault, but I'm not sure.

I'm having another issue as well. Neither tags nor authors are getting inserted into their respective tables. Their insert statement is wrapped in a conditional that's supposed to be making sure they don't already exist, but it seems to be failing and the insert never happens. I assume it's failing because the tags aren't getting put in the database and it's down in the author section before it tosses the error. I know how to do this with pure PHP but I'm trying to go about doing it the pure CI ActiveRecord way.

Here's the statement I'm using:

 if ($this->db->count_all_results() == 0)

And I'm using that instead of what I'd normally use:

if (mysql_num_rows() == 0)

Am I doing it wrong?

Here are my model and controller (only the functions that matter), commented as best I could.

Model:

function new_book($book, $tags, $authors, $read) {

    // Write book details to books table
    $this->db->insert('books', $book);

    // Write tags to tag table and set junction
    foreach ($tags as $tag) {
        // Check to see if the tag is already in the 'tags' table
        $this->db->get_where('tags', array('tag' => $tag));
        // trying to use this like mysql_num_rows()
        if ($this->db->count_all_results() == 0) {
            // Put it there
            $this->db->insert('tags', $tag);
        }
        // Set the junction
        // I only need the id, so...
        $this->db->select('id');
        // SELECT id FROM tags WHERE tag = $tag
        $query = $this->db->get_where('tags', array('tag' => $tag));
        // INSERT INTO books_tags (book_id, tag_id) VALUES ($book['isbn'], $query->id)
        $this->db->insert('books_tags', array('book_id' => $book['isbn'], 'tag_id' => $query->id));
    }

    // Write authors to author table and set junction
    // Same internal comments apply from tags above
    foreach ($authors as $author) {
        $this->db->get_where('authors', array('author' => $author));
        if ($this->db->count_all_results() == 0) {
            $this->db->insert('authors', $author);
        }
        $this->db->select('id');
        $query = $this->db->get_where('authors', array('author' => $author));
        $this->db->insert('authors_books', array('book_id' => $book['isbn'], 'author_id' => $query));
    }

    // If the user checked that they've read the book
    if (!empty($read)) {
        // Get their user id
        $user = $this->ion_auth->get_user();
        // INSERT INTO books_users (book_id, tag_id) VALUES ($book['isbn'], $user->id)
        $this->db->insert('books_users', array('book_id' => $book['isbn'], 'user_id' => $user->id));
    }

}

Controller:

function confirm() {

    // Make sure they got here by form result, send 'em packing if not
            $submit = $this->input->post('details');
    if (empty($submit)) {
        redirect('add');
    }

            // Set up form validation
    $this->load->library('form_validation');
    $this->form_validation->set_error_delimiters('<h3 class="error">', ' Also, you&rsquo;ll need to choose your file again.</h3>');
    $this->form_validation->set_rules('isbn','ISBN-10','trim|required|exact_length[10]|alpha_numeric|unique[books.isbn]');
    $this->form_validation->set_rules('title','title','required');
    $this->form_validation->set_rules('tags','tags','required');

            // Set up upload
    $config['upload_path'] = './books/';
    $config['allowed_types'] = 'pdf|chm';
    $this->load->library('upload', $config);

            // If they failed validation or couldn't upload the file
    if ($this->form_validation->run() == FALSE || $this->upload->do_upload('file') == FALSE) {
        // Get the book from Amazon
                    $bookSearch = new Amazon();
        try {
            $amazon = $bookSearch->getItemByAsin($this->input->post('isbn'));
        } catch (Exception $e) {
            echo $e->getMessage();
        }
                    // Send them back to the form
        $data['image'] = $amazon->Items->Item->LargeImage->URL;
        $data['content'] = 'add/details';
        $data['error'] = $this->upload->display_errors('<h3 class="error">','</h3>');
        $this->load->view('global/template', $data);

            // If they did everything right
            } else {
                    // Get the book from Amazon
        $bookSearch = new Amazon();
        try {
            $amazon = $bookSearch->getItemByAsin($this->input->post('isbn'));
        } catch (Exception $e) {
            echo $e->getMessage();
        }

        // Grab the file info
                    $file = $this->upload->data();

        // Prep the data for the books table
                    $book = array(
            'isbn' => $this->input->post('isbn'),
            'title' => mysql_real_escape_string($this->input->post('title')),
            'date' => $amazon->Items->Item->ItemAttributes->PublicationDate,
            'publisher' => mysql_real_escape_string($amazon->Items->Item->ItemAttributes->Publisher),
            'pages' => $amazon->Items->Item->ItemAttributes->NumberOfPages,
            'review' => mysql_real_escape_string($amazon->Items->Item->EditorialReviews->EditorialReview->Content),
            'image' => mysql_real_escape_string($amazon->Items->Item->LargeImage->URL),
            'thumb' => mysql_real_escape_string($amazon->Items->Item->SmallImage->URL),
            'filename' => $file['file_name']
        );

        // Get the tags, explode by comma or space
                    $tags = preg_split("/[\s,]+/", $this->input->post('tags'));
                    // Get the authors
                    $authors = array();
                    foreach ($amazon->Items->Item->ItemAttributes->Author as $author) {
                        array_push($authors, $author);
                    }
                    // Find out whether they've read it
                    $read = $this->input->post('read');
                    // Send it up to the database
                    $this->load->model('add_model', 'add');
                    $this->add->new_book($book, $tags, $authors, $read);
                    // For now... Later I'll load a view
                    echo 'Success';

    }

}

Could anyone help shed light on what I'm doing wrong? Thanks much.

Marcus

A: 

Where you are using count_all_results(), I think you mean to use num_rows(). count_all_results() will actually create a SELECT COUNT(*) query.

For debugging your problems...
If you want to test if an insert() worked, use affected_rows(), example:

var_dump($this->db->affected_rows());

At any point you can output what the last query with last_query(), example:

var_dump($this->db->last_query());

You can also turn on the Profiler so you can see all the queries being run, by adding in the controller:

$this->output->enable_profiler(TRUE);
Mitchell McKenna
A: 

I managed to figure this out on my own. The controller didn't really change, but here's the new model:

function new_book($book, $tags, $authors, $read) {

    // Write book details to books table
    $this->db->insert('books', $book);

    // Write tags to tag table and set junction
    foreach ($tags as $tag) {
        // Check to see if the tag is already in the 'tags' table
        $query = $this->db->get_where('tags', array('tag' => $tag));
        // trying to use this like mysql_num_rows()
        if ($query->num_rows() == 0) {
            // Put it there
            $this->db->insert('tags', array('tag' => $tag));
        }
        // Set the junction
        // I only need the id, so...
        $this->db->select('id');
        // SELECT id FROM tags WHERE tag = $tag
        $query = $this->db->get_where('tags', array('tag' => $tag));
        $result = $query->row();
        // INSERT INTO books_tags (book_id, tag_id) VALUES ($book['isbn'], $query->id)
        $this->db->insert('books_tags', array('book_id' => $book['isbn'], 'tag_id' => $result->id));
    }

    // Write authors to author table and set junction
    // Same internal comments apply from tags above
    foreach ($authors as $author) {
        $query = $this->db->get_where('authors', array('author' => mysql_real_escape_string($author)));
        if ($query->num_rows() == 0) {
            $this->db->insert('authors', array('author' => mysql_real_escape_string($author)));
        }
        $this->db->select('id');
        $query = $this->db->get_where('authors', array('author' => mysql_real_escape_string($author)));
        $result = $query->row();
        $this->db->insert('authors_books', array('book_id' => $book['isbn'], 'author_id' => $result->id));
    }

    // If the user checked that they've read the book
    if (!empty($read)) {
        // Get their user id
        $user = $this->ion_auth->get_user();
        // INSERT INTO books_users (book_id, tag_id) VALUES ($book['isbn'], $user->id)
        $this->db->insert('books_users', array('book_id' => $book['isbn'], 'user_id' => $user->id));
    }

}
Marcus