Why does CI create a new row instead of updating? - php

I'm creating a UI in my application which will allow the user to decide the state of received content, this includes updating it. How does CI handle this?
I've tried the different update methods provided in the query builder part of the documentation, including replace and update, I pass on the data from the view to the controller, to the model in the form of an array. Yet still, when I try it, it creates a new row with that single value and with all other columns empty.
view.php
<form action="Application/Update" method="get">
<input type="hidden" name="mar-id" value="<?php echo $row['id']; ?>">
<input type="hidden" name="mar-read" value="New-value">
<?php echo anchor('http://localhost/dir/dir/dir/index.php/Application/Update', 'update'); ?>
</form>
controller.php
public function Update() {
$this->load->helper('url');
$this->load->model('Main');
$id = $this->input->post('mar-id');
$value = $this->input->post('mar-read');
$mar = $this->Main->Update($id, $value);
if ($mar == TRUE) {
redirect('http://localhost/dir/dir/dir/index.php/Application/Otherpage', 'refresh');
}
else {
redirect('http://localhost/dir/dir/dir/index.php/Application/Otherpage');
}
}
model.php
public function Update($id, $value) {
$data = array(
'status' => $value
);
$this->db->where('id', $id);
$update = $this->db->update('table', $data);
}
As I said, I expect the row to be updated based on the row-id provided. Instead it creates a completely new row with that single value. It doesn't return any error messages though.

There are a number of mistakes here.
SO to date we have established that performing var_dumps in the controller results in NULL for all your "POST" values.
I've assumed the following for simplicity.
Controller Name is: Program.php (Application is NOT an Allowed controller name as it's a foldername)
Model Name is: Mdl_update.php
View is: update_view.php
Issue #1:
Your Form has an issue where you are using an anchor tag which is just a link. It does nothing in submitting any data from the form.
So we have to remove the Anchor Tag and replace it with a Form Submit. You have to Submit the form to get any chance of sending the form data.
For testing your GET and POST I've added in Two different Forms.
In update_view.php
<!-- Set the Method to GET -->
<form action="program/update" method="get">
<input type="hidden" name="mar-id" value="<?php echo $row['id']; ?>">
<input type="hidden" name="mar-read" value="New-value">
<input type = "submit" name="update" value="Update with GET">
</form>
<!-- Set the Method to POST as this is what the Controller is Expecting -->
<form action="program/update" method="post">
<input type="hidden" name="mar-id" value="<?php echo $row['id']; ?>">
<input type="hidden" name="mar-read" value="New-value">
<input type = "submit" name="update" value="Update with POST">
</form>
What I used to display the Form in the controller by simply calling the program/index in the Program controller.
public function index() {
$this->load->helper('url');
$data['row'] = array('id' => 2);
$data = $this->load->view('update_view', $data, TRUE);
echo $data;
}
So your Controller is looking for POST and not GET. This can be proven by changing the controller up a bit for debugging.
public function update() {
$this->load->helper('url');
$this->load->model('mdl_update');
$id = $this->input->post('mar-id');
$value = $this->input->post('mar-read');
echo '<h2>POST Values</h2>';
var_dump($id);
var_dump($value);
// ****************************
// These are added in for debugging/Demonstration to show values for the form using the GET method.
$id_get = $this->input->get('mar-id');
$value_get = $this->input->get('mar-read');
echo '<h2>GET Values</h2>';
var_dump($id_get);
var_dump($value_get);
// ****************************
exit('Stopped for Debugging: Method '. __METHOD__.' at Line: '.__LINE__); // Added for Debug
$mar = $this->mdl_update->Update($id, $value);
if ($mar == TRUE) {
redirect(base_url('program/otherpage'), 'refresh');
} else {
redirect(base_url('program/otherpage'));
}
}
So you are looking for POST Data when your form method is set to GET. Please be aware of what you are setting. They must match.
If you want to use GET, you need to use $this->input->get()
The code above will let you test both.
So you now have a POST and GET Form and the controller is setup to demonstrate the two different types. Choose Either GET or POST!. That is up to you on which one you choose.
Issue #2: Expecting a return value from your Model when you are not returning anything.
In your Controller you have the line...
$mar = $this->mdl_update->Update($id, $value);
And in your Model you have...
public function update ($id,$value) {
$data = array(
'status' => $value
);
$this->db->where('id', $id);
$this->db->update('db_table', $data);
}
Your Model Method is not returning anything.
You should always look up what your return values are. I am expecting that your intention was to return the value of the update. Looking through the CI Code itself it appears that if things go wrong it will return FALSE (if the database debug is disabled - learnt something new)
I've added in some debug to assist in viewing what is going on here.
public function update($id, $value) {
$data = array(
'status' => $value
);
$this->db->where('id', $id);
$update_result = $this->db->update('db_table', $data);
echo $this->db->last_query(); // Added for DEBUG
return $update_result;
}
Now I cannot get your code to create new rows as you claim. It's impossible, with this code, to add new rows. So thats happening from something you haven't shown us but that is an aside and not important here.
If we alter the controller to view the model etc (I am only showing the changes ) we would change
exit('Stopped for Debugging: Method '. __METHOD__.' at Line: '.__LINE__);
$mar = $this->mdl_update->Update($id, $value);
To this
$mar = $this->mdl_update->Update($id, $value);
var_dump($mar);
exit('Stopped for Debugging: Method '. __METHOD__.' at Line: '.__LINE__);
If you run this and submit either the GET ( Results are NULL ) or POST, the update will always return TRUE. So your redirect etc needs to be looked at on how you decide on one or the other.
I think you should set your table columns to not allow them to be NULL AND add in some "Validation" in your controller.
ISSUE 3: No Form Validation
CodeIgniter has a Form Validation Class that I suggest you read. This is getting way too long to go into that here...
So as you go through this, you can add/remove debugging to test what is going on and progress it along the way as I have hopefully shown.
if anything is unclear, just ask. I'm sure I may have left something out.

Related

Deleting a database record using codeigniter

Ok, Struggling abit here, I'm pretty new to codeigniter and quite new to PHP. I want to delete a record from the DB. I'm getting an error with the controller. Here is my code
Controller:
public function removeitem(){
$this->load->helper(array('form', 'url'));
$this->load->view('vRemove');
}
public function doremove(){
$this->load->model("mphoto");
$this->mphoto->removeItem($id);
$this->load->view('removed_success');
}
Model:
public function removeItem($id){
$this->db->where('ProductID', $id);
$this->db->delete('Streamline');
}
and View:
<?php echo form_open_multipart('site/doremove');?>
<p>Are you sure you want to remove this item?</p>
<a href="<?php echo base_url();?>index.php/site/admin">
<input type="button" value="Cancel" />
</a>
<div><input type="submit" value="Submit" /></div>
</form>
<?php ?>
Error I'm getting is:
A PHP Error was encountered
Severity: Notice
Message: Undefined variable: id
Filename: controllers/site.php
Line Number: 114
Which is this line:
$this->mphoto->removeItem($id);
EDIT: The error no longer exists after changing the following code in the controller but the problem now is that the item from the database is not being deleted.
public function doremove(){
$this->load->model("mphoto");
$id = $this->input->get('ProductID');
$this->mphoto->removeItem($id);
$this->load->view('removed_success');
}
Any help is greatly appreciated.
$id in the controller's doremove() function is undefined. You need to pass a the value of the ID from the view to the controller; there are a couple of common ways to achieve this.
URI segment parameter (GET)
Pass the ID through a URI segment. For example: http://yousite.com/site/doremove/2 would pass 2 as the parameter to the doremove function in the site controller.
View
<p>Are you sure you want to remove this item?</p>
// Change 2 to the id of the product you want to remove - you can do this dynamically
Yes
// Add cancel button etc...
Controller
public function doremove($id = null) {
if ($id === null)
{
// The ID isn't set - show an appropriate message, redirect, whatever you want...
}
else
{
$this->load->model("mphoto");
// Is the delete operation sucessful?
if ($this->mphoto->removeItem($id))
$this->load->view('removed_success');
else
$this->load->view('removed_failure'); // Or whatever you want
}
}
Through a form (POST)
View
<?php echo form_open('site/doremove');?>
<p>Are you sure you want to remove this item?</p>
// Change 2 to the id of the product you want to remove
<input type="hidden" name="product_id" value="2" />
<input type="submit" value="Submit" />
</form>
Controller
public function doremove() {
$id = $this->input->post('product_id');
if($id)
{
$this->load->model("mphoto");
// Is the delete operation sucessful?
if ($this->mphoto->removeItem($id))
$this->load->view('removed_success');
else
$this->load->view('removed_failure'); // Or whatever you want
}
else
{
// The ID isn't set - show an appropriate message, redirect, whatever you want...
}
}
It'd also be a good idea to check if the action performed on the database is successful.
Model
public function removeItem($id) {
// Attempt to delete the row
$this->db->where('ProductID', $id);
$this->db->delete('Streamline');
// Was the row deleted?
if ($this->db->affected_rows() == 1)
return TRUE;
else
return FALSE;
}
In the function doremove() $id is undefined, you need to take the $id of the resource
If the HTTP method is GET, you need to use the $id = $this->input->get('the_input_name');
or if is POST, $id = $this->input->post('the_input_name');
or you can use a user friendly way, passing the $id in the function scope, doremove($id), just make shure your URL is set properly ('site/doremove/$id').
Read the User Guide, it will make a big difference in your code.
In this link have a good example of a simple form using codeigniter: http://ellislab.com/codeigniter/user-guide/libraries/form_validation.html

How to call class method as form action php mvc application if it's even possible?

I'm trying to write a simple mvc application with php and mysql. I'm very new to mvc and relativly new to php aswell. I'm letting the user choose from different movies and then add the ones they want to their own list. But I can't figure out how to get the correct form action to insert the choosen movie into the db.
This is how my two model class methods looks like:
public function checkMovie() {
// Check if movie exist in db.
$stmt = $this->dbh->prepare("SELECT * FROM watchlist WHERE my_title='{$_POST['my_title']}'");
$stmt->bindParam(':my_title', $_POST['my_title']);
$stmt->execute();
$rows = $stmt->fetchALL();
$this->n = count($rows);
}
public function addMovie() {
// Add choosen movie to db.
$sql = $this->dbh->prepare("INSERT INTO watchlist(my_title, my_des, my_link)
VALUES ('{$_POST['my_title']}', '{$_POST['my_des']}', '{$_POST['my_link']}')");
$sql->bindParam(':my_title', $_POST['my_title'], PDO::PARAM_STR);
$sql->bindParam(':my_des', $_POST['my_des'], PDO::PARAM_STR);
$sql->bindParam(':my_link', $_POST['my_link'], PDO::PARAM_STR);
$sql->execute(array(':my_title' => $_POST['my_title'],':my_des' => $_POST['my_des'],':my_link' => $_POST['my_link']));
}
As you can see I have the basic sql-code in here and then I call the methods from a method in my controller:
public function getAddMovie() {
$this->addModel = new AddMovieModel();
if (isset($_POST['submit'])) {
// Call checkmovie from addmoviemodel and check if movie allready is taken.
$checkmovie = $this->addModel->checkMovie();
if($this->n > 0) { // Should this logic perhaps be in my model?
// Shows javascript-popup eg. 'movie allready added'.
include 'view/viewscripterror.php';
}
else { // Call addMovie from addmoviemodel to insert movie to db.
$addmovie = $this->addModel->addMovie();
// Shows javascript-popup eg. 'movie is now added'.
include 'view/viewscriptsuccess.php';
}
}
}
I'm not sure if the if($this->n > 0) perhaps should be in my model aswell?
And here's the form, I can't figure out what to pass as form action? This problem has been driving me crazy for a while now and that's why I'm turning here in hope for some help.
echo '<form action="??" method="post">',
'<input type="hidden" name="my_title" value="'.$title.'">',
'<input type="hidden" name="my_des" value="'.$description.'">',
'<input type="hidden" name="my_link" value="'.$link.'">',
'<input type="submit" name="submit" value="Peppa!">',
'</form></div>';
Try like
echo '<form action="http://site_url/getAddMovie" method="post">',
You need to pass the url of the function getAddMovie into the action,then after submitting it,it will post/get the params into that function.
And try to load the model like
$this->load->model('AddMovieModel');
And try to call it like
$checkmovie = $this->AddMovieModel->checkMovie();
Or even you can try like
$addModel = new AddMovieModel();
and call it like
$checkmovie = $addModel->checkMovie();

my update query didn't work on Codeigniter

I have a table name "Category" which contains (cat_id, name, description). I can insert, retrieve, and delete without any problems. But when I update my Category, no data inserted in my database. I check my table and the result is nothing.
The POST model "Category_Model extends CI_Model":
public function custom_query($data)
{
$q = $this->db->query($data);
return $q;
}
The POST controller "Category extends CI_Controller":
public function edit_category()
{
$data['title'] = "Edit Category Page";
$this->load->view('edit_category', $data);
}
public function update_category()
{
$id = $this->input->post('cat_id'); // I try $id = $this->uri->segment(3); but no result
$name = $this->input->post('name');
$desc = $this->input->post('description');
$this->post_model->custom_query("update category set cat_name='".$name."', description='".$desc."' where cat_id='".$id."'"); // when I delete 'where cat_id='".$id."'' clause, all my records were changing/updating
// I change to $this->db->where('cat_id', $id); $this->db->update('category'), but no result.
redirect ('category/view_categories');
}
Here is my EDIT CATEGORY view:
<form action="<?php echo base_url(); ?>category/update_category" method="POST">
<fieldset>
<legend>Edit Category</legend>
<label for="cat">Name :</label>
<input type="text" name="name"/>
<label for="desc">Descriptions :</label>
<textarea name="description" cols="40" rows="2"></textarea>
<input type="submit" value="Update">
</fieldset>
</form>
Please anyone tell me what was wrong with my code? Thank in advance
best regards.
*note: I put 'database' in autoload config.
First of all, are you sure you writing table name correctly?
..."update kategori..."
If this is ok, try to output your query before sending it to database, like this:
$query = "update kategori set cat_name='".$name."', description='".$desc."' where cat_id='".$id."'";
error_log('My query: ' . print_r($query, true));
$this->post_model->custom_query($query);
Then, if you won't see any problems in that query, give it to us.
It looks like your query might not be getting the cat_id as I don't see it anywhere in the passing view. Try a hidden field in the HTML which contains the cat_id. This might also be easier than trying to get it via URI segments.
You could be learn about CI models, it will simplify your life.
I believe with, for some reason, the redirect could be close your connection before the commit... It doesn't occur if you use the model object.
A little sample for models...
Create a class on application/models, like this
file "category_model.php"... attention for this name, because the CI is very restrictive with model name. Must by equal class name, but all lowercase.
class Category_model extends CI_Model {
// your fields
var $id = null;
var $name = null;
// call parent constructor... it's essential
function __construct() {
parent::__construct();
}
// create a set function, for fill all fields directly from get or post
function set($data) {
$this->id = isset($data['id']) ? $data['id'] : null;
$this->name = isset($data['name']) ? $data['name'] : null;
}
// execute update on database
function update($id) {
$this->db->update('category', $this, array('id' => $this->id));
}
}
on the controller, instance and invoke the model
$this->load->model('Category_Model', null, true);
$this->Category_Model->set($this->post());
$this->Category_Model->update();
after this, proceed you normal code.

PHP Concrete 5 Pass Variables to Add.php

I'm creating a new block and I want to pass a defined variable to the block instance on add.
In my controller, I have the following:
// declare the var
public $hasMap = 0;
public function add() {
$this->set('hasMap', $this->generateMapNumber());
}
The generateMapNumber() function looks like this:
public function generateMapNumber() {
return intval(mt_rand(1,time()));
}
In my add.php form I have a hidden field:
<?php $myObj = $controller; ?>
<input type="hidden" name="hasMap" value="<?php echo $myObj->hasMap?>" />
When I create a new block, hasMap is always 0 and the hidden input value is always 0 too. Any suggestions? Thank you!
--- EDIT ---
From the concrete5 documentation:
// This...
$controller->set($key, $value)
// ... takes a string $key and a mixed $value, and makes a variable of that name
// available from within a block's view, add or edit template. This is
// typically used within the add(), edit() or view() function
Calling $this->set('name', $value) in a block controller sets a variable of that name with the given value in the appropriate add/edit/view file -- you don't need to get it from within the controller object. So just call <?php echo $hasMap; ?> in your add.php file, instead of $myObj->hasMap.
It will not be the same value, because the function will give diferrent values every timy it is called.
So here's the solution. In the controller...
public $hasMap = 0;
// no need for this:
// public function add() { }
public function generateMapNumber() {
if (intval($this->hasMap)>0) {
return $this->hasMap;
} else {
return intval(mt_rand(1,time()));
}
}
And then in the add.php file...
<?php $myObj = $controller; ?>
<input type="hidden" name="hasMap" value="<?php echo $myObj->generateMapNumber()?>" />
It works perfectly. On add, a new number is generated and on edit, the existing number is drawn from the hasMap field in the db.
Thanks for all the input. Hope that helps someone else!

Codeigniter delete multiple rows with checkboxes

I'm trying to delete multiple private messages from my database by selecting multiple checkboxes in the inbox and clicking submit to delete. I have the code below but nothing happens. I'm not sure what I'm missing..
View:
<?php echo form_open('pm/remove_checked'); ?>
<?php foreach ($query as $row): ?>
<input type="checkbox" name="msg[]" value="<?php echo $row->id; ?>" />
<?php echo $row->from; ?>
<?php echo $row->subject; ?>
<?php echo date("m/d/Y",strtotime($row->msg_date)); ?>
<?php endforeach; ?>
<?php echo form_submit('delete', 'Delete'); ?>
</form>
Controller:
function remove_checked()
{
//validation rules
$this->form_validation->set_rules('msg[]', 'Private Message', 'required|xss_clean');
if ($this->form_validation->run() == FALSE)
{
$data['query'] = $this->Pm_model->received_msg();
$this->load->view('pm/inbox', $data);
}
else //success
{
$checked_messages = $this->input->post('msg'); //selected messages
$this->Pm_model->delete_checked($checked_messages);
//redirect to inbox
}
}
Model:
function delete_checked($checked_messages)
{
$checked_messages = array();
foreach ($checked_messages as $msg_id):
$this->db->select('id');
$this->db->from('user_msg');
$this->db->where('id', $msg_id);
$this->db->limit(1);
$query = $this->db->get();
if ($query->num_rows() > 0) //if message exists
{
$this->db->where('id', $msg_id);
$this->db->where('recipient', $this->users->get_user_id()); //verify if recipient id is equal to logged in user id
$this->db->delete('user_msg');
}
else
{
return FALSE;
}
endforeach;
}
In your current delete_checked() method, you are returning FALSE as soon as the first message is "found" that doesn't exist, this will prevent the rest of the messages from being deleted as return will stop execution of the loop. If you want to do it this way, use continue instead and consider using transactions.
If you don't particularly care about generating individual errors for each message, your model function can be simplified a bit:
function delete_checked($message_ids)
{
$this->db
->where_in('id', $message_ids)
->where('recipient', $this->users->get_user_id())
->delete('user_msg');
return $this->db->affected_rows() > 0;
}
This will just attempt to delete the records. If they don't exist they will be ignored, and $this->db->affected_rows() should return the number of messages deleted. You can compare it to count($message_ids) if you want to ensure that all messages selected were deleted, or use this example method that only checks if at least one message was deleted. If the message doesn't exist, you don't need to delete it anyways.
All the stuff Chris Schmitz mentioned is correct and important as well, you have some very basic errors. You may want to cast to array instead of assigning $checked_messages to an empty array if you expect you may be passing a single id (integer or string) to this function. Like this:
$message_ids = (array) $message_ids;
You are assigning $checked_msg to the inputs that are checked, but then you are passing a different variable called $checked_messages to the model. You'll want to pass the $checked_msg var to the model.
Also, in your model, you are redeclaring the $checked_messages var and setting it to an empty array. You'll need to remove that otherwise it will overwrite the info you are passing to the method.

Categories