Problem with query to update foreign key column - php

I am working on a cms for properties/ads in oop php for learning purposes. I have three tables that are connected with pivot table.
photos (id, name, extension),
property_photo (id, property_id, photo_id),
properties (id, title, description, main_photo_id)
I have a gallery of photos for every property and I am trying to be able to insert main photo (one of existing photos in gallery) for each property through foreign key (main_photo_id) and display that photo on a different page. I am having trouble writing function (query) in model. Any help is much appreciated. Here is some of my code:
AdModel:
public function MainPhotoInsert($id)
{
$this->db->query('INSERT INTO properties (main_photo_id) VALUES (:main_photo_id) SELECT id FROM PHOTOS WHERE id = :id LIMIT 1');
$this->db->bind(':id', $id);
$row = $this->db->single();
return $row;
}
AdsController:
public function galleryAction()
{
if (!isset($_GET['id'])) {
$photo_id = $_SESSION['photo_id'];
} else {
$photo_id = $_GET['id'];
}
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
if(isset($_POST['radio']))
{
$this->AdModel->MainPhotoInsert($photo_id);
redirect('ads/index');
}
}
$data = $this->AdModel->getPhotosForProperty($photo_id);
$data1 = $this->AdModel->MainPhotoData($photo_id);
$this->view->render('ads/gallery', $data, $data1);
}
gallery.php:
<form action="/ads/gallery?id=<?php echo $_GET['id']; ?>" method="POST">
<?php foreach ($data as $key => $value) : ?>
<img src="<?php echo '/public/photos/'.$value->name.'.'.$value->extension ?>" class="img-fluid img-thumbnail" width="250" height="250">
<input type="radio" name="radio" value="<?php echo $value->photo_id; ?>" >Make main
<br>
<?php endforeach; ?>
<br>
<br>
<button type="submit" name="submit" value="submit" class="btn btn-success form-control">Submit</button>
</form>

You shouldn't have a select clause in your insert statement (at least not for what you are trying to do). IF you only ever need to set it once then you need to tweak the query to include the other two values (title and description) or they will always be blank. It should end up looking something like this:
INSERT INTO properties (main_photo_id, title, description) VALUES (:main_photo_id, : title, : description)
More likely, you want an upsert (update if a relevant row already exists, insert if one doesn't). In MySQL the syntax is insert ... on duplicate key update. This means you are going to need a primary key on the properties table (it's unclear if you already have one). The syntax is pretty similar to the insert above but without knowing the exact structure of the table I can't give you the exact query.
Update:
The on duplicate key syntax would look something like this (it depends on how you have your primary key set up on the table, e.g. if main_photo_id is the primary key then this likely won't work):
INSERT INTO properties
(id, main_photo_id, title, description)
VALUES
(:id, :main_photo_id, : title, : description)
ON DUPLICATE KEY UPDATE
main_photo_id = :main_photo_id,
title = :title,
description = :description
Side note:
gallery.php is also going to produce a separate HTML form for each image with one radio button on the form which isn't really what you want. You should move the form to wrap around the entire foreach loop so that you have one form. Then you should put the image ID as the value for the radio button.

Related

PDO multiple checkboxs inserting or delete

I need help to link between three tables by checkboxe:
features table ( id, title, sulg )
posts table (id, title, slug, added )
posts_features ( fea_id, post_id )
<input type="text" name="title" value="$post->title">
<input type="text" name="slug" value="$post->slug">
// importing all features
<input type="checkbox" name="featuresid[]" value="$features->id">
If checked ( insert ) if not exist.
foreach ($_POST['featuresid'] as $choice) {
$sql = $dbh->prepare("INSERT INTO posts_features (fea_id, post_id) VALUES ($choice, $id)");
$sql->execute();
}
and if un-checked ( delete ) from posts_features
$sql = $dbh->prepare("delete form posts_features where ........
Thanks in advance.
A checkbox doesn't $_POST if it's not checked, so you would not have a way to see (from the $_POST, anyway) which features where not checked.
There's several ways to do this, but without more information about your application, it's hard to make the "best" suggestion, but here's one method that will leverage $_POST:
Add an additional "hidden" input, with the corresponding $features->id, to set up the "existing" entries:
Note: I'm following your conventions in your code above to demonstrate this, even though they are clearly pseudo-code, and won't work properly.
<input type="checkbox" name="featuresid[]" value="$features->id">
<input type="hidden" name="existing[]" value="$features->id">
Then, you can leverage your loop like so:
foreach ($_POST['featuresid'] as $choice) {
$sql = $dbh->prepare("INSERT INTO posts_features (fea_id, post_id) VALUES ($choice, $id)");
$sql->execute();
}
// loop through ALL feature ids listed on the page
foreach( $_POST['existing'] AS $features_id ) {
// if the feature id wasn't in the checkboxes, then delete
if ( ! in_array( $features_id, $_POST['featuresid'] ) ) {
$sql = $dbh->prepare("DELETE FROM posts_features WHERE ........");
}
}
Un-checked checkboxes are not sent to PHP. So as you iterate through $_POST['featuresid'], you will only see the checkboxes that were checked. This means that to delete unchecked features really means to delete all features that are not in the checked group.
First, insert the selected features: important don't execute DB queries in a loop; they will really slow down your script. Instead, insert all records at once. You should also use parameterized queries; never insert user-supplied values directly into your DB queries!
After the insert, delete those features that were not selected:
DELETE FROM posts_features WHERE fea_id NOT IN (?, ?, ?, ?)
Each of the ? corresponds to a value in $_POST['featuresid']
An alternative, if you want PHP to receive an explicit selected/unselected value for each feature is to use Yes/No radio buttons or dropdown list for each feature in the HTML.

Linking existing MySQL records in new query, PHP/PDO

$insert = $dbh->prepare('INSERT INTO tags (tag_name) VALUES (:tag)');
$insert->bindParam(':tag', $tag, PDO::PARAM_STR);
foreach($tags as $tag) {
$insert->execute();
$tag_id = $dbh->lastInsertID();
echo $tag_id."+".$photo_id."<br />";
$sql = "INSERT INTO tagrefs (tag_id, photo_id) VALUES (:tag_id,:photo_id)";
$q = $dbh->prepare($sql);
$q->execute(array(':tag_id'=>$tag_id,
':photo_id'=>$photo_id));
}
This particular piece of code inserts tags related to uploaded photos into a table called 'tags'. It links the tag_id to the photo_id in a table called 'tagrefs'. This all works fine, until I use a tag twice. Which is logical, because nothing is inserted (tags are unique, I simply want the entry in 'tagrefs' to list the photo_id for my next photo with tag_id's that already exist)
How do I make it so that my code compares the tags the user put in and compares them, or that the values of existing tags are returned and put into 'tagrefs' properly? Thank you very much in advance for your time.
If you use INSERT ... ON DUPLICATE KEY UPDATE, then lastInsertID() will return the AUTO_INCREMENT field's value of a matched row even if an UPDATE is performed instead of an insertion.
To ensure that it also works in versions of MySQL prior to v5.1.12, one can explicitly set the insertion id with MySQL's LAST_INSERT_ID() function:
INSERT INTO tags
(tag_name)
VALUES
(:tag)
ON DUPLICATE KEY UPDATE
id = LAST_INSERT_ID(id)

Get the id of current mysql insert

is there anyway to get the ID of the current record I am INSERTING into the database table using php with Mysql without having to do an extra select to get the last ID?
FOr example, if my table has these columns, id, url, name
and if url consists of the domain name and current id as the query variable ex:
domainname.com/page.php?id=current_id
$sql="INSERT INTO Persons (id, url, name )
VALUES
('domainname.com/page.php?id=".**whats_the_current_id**."','$_POST[age]')";
if (!mysql_query($sql,$con))
{
die('Error: ' . mysql_error());
}
as far as I know, there is no 'clean' way to find the ID you are about to insert (from what I understand from your question, this is what you want to know).
Two options in my opinion, starting with the ugly one: select max(id) from Persons, increment it with one, and hope that no insert's will mess this up for you. Like I said, its ugly, and -not- reliable.
A better option would be to first insert the record with a dummy value for url, and then retrieving the just inserted row's ID with mysql_insert_id(). Then update that record with the correct url value.
You asked for a way to retrieve the id without a select query following the insert query, but like I said, I don't think this is possible.
i use mysql_insert_id() for that. it works fine.
// pseudo-ish code
$query = "INSERT something .... "
$updated = $db->run_query($query);
$id = mysql_insert_id();
your table should be like this
ID AUTO_INCREMENT
person_id VARCHAR
person_url ...
person_name ...
your post form something like
<form method="post">
<input type="hidden" name="id" value="<?php echo uniqid() ?>" />
...
</form>
the query should be like this:
$person_id = intval($_POST['id']);
$person_url = mysql_real_escape_string($_POST['url']);
$person_name = mysql_real_escape_string($_POST['name']);
mysql_query("INSERT INTO Persons (person_id, persno_url, person_name) VALUES ( {$person_id} , {$person_url}, {$person_name} )");
$ID = mysql_insert_id();
The current ID is in $_GET['id']. You should sanitize it before inserting it into your query:
$id = intval($_GET['id']);
Then, use $id in your query.
If you add classes around the first insert and then the second select. The select will work then.
<?php
class insert1{
function inserthere(){
***insert***
}
}
class select1{
function selecthere(){
***select***
}
}
$a = new insert1;
$a->inserthere();
$b = new select1;
$b->selecthere();
?>

Update row if there is a value or insert if not

I have a form where the user inserts data but they can go back to the same page to edit their information. My table structure is:
id (auto int index),
user id (links to other tables),
Doc_Name,
Abstract
I have an insert query:
$user_id = intval($_SESSION['user_id']);
$Doc_Name = mysql_real_escape_string($_POST['Doc_Name']);
$abstract = mysql_real_escape_string($_POST['abstract']);
$the_query = sprintf("INSERT INTO `document` (`user_id`,`Doc_Name`,`abstract`) VALUES
('%d','%s','%s')", $user_id, $Doc_Name, $abstract);
However, if their is already a row for this user_id then I want the update query instead:
mysql_query("UPDATE document SET `Doc_Name` = '$Doc_Name', 'abstract='$abstract'
WHERE id='$_SESSION[user_id]'") or die(mysql_error());
Also, so the user knows what they entered, I tried to use this echo in the text box but that didn't work either,
<textarea name="Doc_Name" style="width:500px; height:150px" type="text" id="Doc_Name"
value="<? echo $row_settings['Doc_Name']; ?>" size="300"> </textarea>
You can use INSERT ... ON DUPLICATE KEY UPDATE Syntax
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE
c=c+1;
You want the INSERT ... ON DUPLICATE UPDATE syntax
for the textarea you can use
<textarea name="Doc_Name" style="width:500px; height:150px" type="text" id="Doc_Name" size="300"><? echo $row_settings['Doc_Name']; ?></textarea>
everything between the tags is displayed and editable
EDIT: to the other posters: nice, did not know INSERT ON DUPLICATE
the query:
SELECT * FROM document WHERE id='{$SESSION['user_id']}'
php:
if(mysql_num_rows(mysql_query($query)) > 0) {
//code to be executed if id exists
}

mysql query to insert photo details in database tables

I want to build a query to insert photo details in database tables. Here's my tables structure:
photos(photo_id, photo_title, caption, ....)
tags(tag_id, tag_name)
tag_asc(tag_id, photo_id)
A photo has title, caption, and tags array. I want to:
Insert photo_title and caption in photos table.
Insert each of tag from tags array in tags table.
Insert tag_id and photo_id in tag_asc table (to link tags with photos).
I have come up with following three queries to do above task.
mysql_query("INSERT INTO photos (photo_title, caption)
VALUES ($title, $caption)");
$photo_id = mysql_insert_id(); //get photo_id
foreach ($tags as $tag){
mysql_query("INSERT INTO tags (tag_name)
VALUES ($tag)");
$tag_id = mysql_insert_id(); //get tag_id
mysql_query("INSERT INTO tag_asc (tag_id, photo_id)
VALUES ($tag_id, $photo_id)");
}
My question
If the above approach is good, or if there is more efficient way to do same thing?
Most of what you're doing looks fine. The main problem I see is the potential for duplicate tags.
It would be better to check if a tag exists and fetch the existing tag's ID if it does, rather than creating a new tag each time. This would prevent duplicate tag names from being inserted into the tags table. If you know each tag is unique, this could speed things up later — for example, you could search photos by their tag IDs rather than having to do some messy JOIN stuff.
Give tags.tag_name a unique index if it doesn't have one already.
Use the following function to fetch a tag ID. If the tag already exists, the existing row ID will be returned. If not, a new row will be created and its ID will be returned.
-
function select_or_create_tag($tag_name) {
$tag_name = addslashes($tag_name);
$result = mysql_query("SELECT id FROM tags WHERE tag_name='$tag_name'");
if ( mysql_num_rows($result) > 0 )
return mysql_result($result, 0, 0);
$insert = mysql_query("INSERT INTO tags (tag_name) VALUES ('$tag_name')");
return mysql_insert_id($insert);
}
Example usage, based on your code:
mysql_query("INSERT INTO photos (photo_title, caption)
VALUES ($title, $caption)");
$photo_id = mysql_insert_id();
foreach ( $tags as $tag ) {
$tag_id = select_or_create_tag($tag);
mysql_query("INSERT INTO tag_asc (tag_id, photo_id)
VALUES ($tag_id, $photo_id)");
}
Also:
Make sure you have non-unique indices set up on tag_asc.tag_id and tag_asc.photo_id for faster querying.
As OMG Ponies mentioned, it might be worth converting this code to a stored SQL procedure. That would get rid of a lot of the overhead involved with making all these SQL queries individually.

Categories