PDA

View Full Version : going from a db to Flash and back again...


Scuba_Steve
07-06-2007, 03:36 PM
Ok folks i'm running around in circles trying to figure out why this won't work. What i'm looking to create is an app that allows people to log into a database and retrieve information in an "items" table for all items linked to their login name (email address).

So far everything works fine. The first part of my flash app handles the login and sends their login info to a php script that verifies the credentials and sends a value back to the flash app that allows it to play to the next section. In this next section, a 2nd php script pulls info from the "items" table based on the user's login name and sends that item info back to flash. flash then loops through and puts the data into a multi-dimensional array which is then set as the dataProvider for a datagrid.

I want users to be able to edit data within the datagrid and then be able to click "Save Changes" at which point Flash loops through the newly updated multi-dimensional array and updates the "items" table via a 3rd php script.

I'm at the point where I can pull the info down based on the username and populate the datagrid. Problem is, when I make changes and hit "Save Changes", those changes aren't reflected in the database. :confused:

I've posted my actionscript below as well as the 2 php scripts in question. If anyone can help me sort this out, there's $20 in it for you.


stop();
mc_confirmReset._visible = false;

saveChanges_btn.addEventListener("click", saveChanges);
reset_btn.addEventListener("click", resetGrid);

var fetch_lv:LoadVars = new LoadVars();
fetch_lv.username = _global.username; // sends our username to the php script so we know what products to query
// fyi this global var was defined earlier in the flash app so i know it's valid:)
var retrieve_lv:LoadVars = new LoadVars();

fetch_lv.sendAndLoad("http://www.mydomain.com/path/to/my/gridfeeder.php", retrieve_lv, "POST");

var prodArray:Array = new Array();

retrieve_lv.onLoad = function(success:Boolean) {
// If Flash is able to successfully send and load the variables from the server-side script...
if (success) {
trace ("Loading " + this.numRows + " products linked to " + this.username + "...");
var numRows:Number = this.numRows;
for (var i:Number = 0; i<numRows; i++) {
prodArray[i] = new Array();
prodArray[i]["Qty"] = this["invlevel" + i];
prodArray[i]["Use Inv"] = this["useinv" + i];
prodArray[i]["S-Price"] = this["saleprice" + i];
prodArray[i]["R-Price"] = this["regprice" + i];
prodArray[i]["Sale Type"] = this["pricestatus" + i];
prodArray[i]["Name"] = this["name" + i];
prodArray[i]["P/N"] = this["prodnum" + i];
};

setupGrid();
};
};

function setupGrid() {
productGrid.dataProvider = prodArray;
productGrid.editable = true; // To lock columns you have to make the whole grid editable and then certain columns uneditable...
productGrid.setStyleProperty("WordWrap", true);
productGrid.getColumnAt(0).editable = false; // We don't want them to be able to edit "P/N"
productGrid.getColumnAt(1).editable = false; // or "Name" columns.
productGrid.getColumnAt(0).width = 100;
productGrid.getColumnAt(1).width = 160;
productGrid.getColumnAt(2).width = 70;
productGrid.getColumnAt(3).width = 60;
productGrid.getColumnAt(4).width = 50;
productGrid.getColumnAt(5).width = 50;

};

var saveData_lv:LoadVars = new LoadVars();
var wasItSaved_lv:LoadVars = new LoadVars();

var continueOn:String = "Yes";
function saveChanges(){
trace("saveChanges() function triggered...");
for (var i:Number = 0; (i<prodArray.length) && (continueOn="Yes"); i++){
continueOn = "No";
saveData_lv.productNum = prodArray[i]["P/N"];
saveData_lv.newSaleType = prodArray[i]["Sale Type"];
saveData_lv.newRegPrice = prodArray[i]["R-Price"];
saveData_lv.newSalePrice = prodArray[i]["S-Price"];
saveData_lv.newUseInv = prodArray[i]["Use Inv"];
saveData_lv.newQty = prodArray[i]["Qty"];
saveData_lv.sendAndLoad("http://www.mydomain.com/path/to/my/gridsaver.php", wasItSaved_lv, "POST");
wasItSaved_lv.onLoad = function(success:Boolean){
if (success){
continueOn = this.continueOn;
trace("wasItSaved_lv onLoad function triggered");
};
};
trace ("continueOn: " + continueOn);
trace ("saveData_lv.productNum =" + saveData_lv.productNum);
trace ("saveData_lv.newRegPrice = " + saveData_lv.newRegPrice);

};
setupGrid(); // need this to make sure productArray is loaded with saved data bounced back from the db.
};


Note: the "continueOn" crap was my pathetic attempt to force that loop to run synchronously... I thought perhaps that my actionscript was hammering the php script that actually updated the database but when i stuck those trace statements into the function to see who was being trigger when, i found that the loop just kept running regardless of the onLoad being in there...

Now, the PHP scripts...

This one pulls the data I want based on the user's login name and sends it to Flash:

<?php // gridfeeder.php

$username = $_POST['username'];

include("login_info.php");

$connect = mysql_connect($host, $user, $pass);

if (!$connect){

die ("Feed unavailable.");
} else {

mysql_select_db($database, $connect);
$query = "SELECT prodnum, name, pricestatus, regprice, saleprice, useinv, invlevel FROM items WHERE shipemail='$username'";
$result = mysql_query($query);
$numRows = mysql_num_rows($result);

$toFlash = "&username=$username&numRows=$numRows";

$i = 0;
while($row=mysql_fetch_array($result)){
$toFlash .= "&prodnum$i=$row[prodnum]&name$i=$row[name]&pricestatus$i=$row[pricestatus]&regprice$i=$row[regprice]&saleprice$i=$row[saleprice]&useinv$i=$row[useinv]&invlevel$i=$row[invlevel]";
$i++;
};

};

echo $toFlash;

mysql_close($connect);

?>


And this script is SUPPOSED to receive the new item information and update the database accordingly:

<?php // gridsaver.php

$productNum = $_POST['productNum'];
$newSaleType = $_POST['newSaleType'];
$newRegPrice = $_POST['newRegPrice'];
$newSalePrice = $_POST['newSalePrice'];
$newUseInv = $_POST['newUseInv'];
$newQty = $_POST['newQty'];

include("login_info.php");

$connect = mysql_connect($host, $user, $pass3);

if (!$connect){

die ("Feed unavailable.");

} else {

mysql_select_db($database, $connect);
$query = "UPDATE items SET pricestatus='$newSaleType', regprice='$newRegPrice', saleprice='$newSalePrice', useinv='$newUseInv', invlevel='$newQty' WHERE prodnum='$productNum'";
$result = mysql_query($query);
$response = mysql_num_rows($result);
$continueOn = "Yes";


};

echo "&response=" . $response . "&continueOn=" . $continueOn;

mysql_close($connect);

?>


Any ideas? Been fudging with it for 2 weeks now but just keep banging my head against the wall.:o

v/r,
Steve

hobbis
07-07-2007, 01:10 AM
I take it you can save a simple text value to the database can't you? ie. breaking your scripts right donw to it's minimal functionality then building it back up again. Can't see anything obvious though. How large is the data you are sending up to PHP?

BTW have you tried AMFPHP? A bit of Flash Remoting? It would be ideal for this sort of thing.

peptobismol
07-07-2007, 01:33 AM
man, who can afford those flash servers?

umm. If you haven't already, create a relational database... Look up that term and it should show you what to do... Basically, it'll keep your data in different tables for easy referencing like userid & info relating to that uid.

And what I find useful is to spit back and forth the info in xml format. It's easier to manage than that &a=1&b=2&c=3& stuff.

LOLFlash
07-07-2007, 02:12 AM
amfphp is free and written by real programmers <-> it works. (thanks Patrick)

peptobismol
07-07-2007, 04:53 AM
sweet.

ps. .you do need you're own server to install in the ( htdocs) web server folder right?

LOLFlash
07-07-2007, 02:10 PM
if you have PHP running just copy and paste amfphp folder on your server. Done. You have native Flash object communication

Scuba_Steve
07-09-2007, 01:17 PM
yeah i have amfphp and even installed it. ;) to be honest i just haven't taken a good enough look at the documentation.

pepto - yeah i've got another script that does exactly that - puts the data into XML for importing into flash. problem was i couldn't get it to import because of the stupid doctype. if i didn't specify a doctype, the php wouldn't be rendered by IE as xml, and if i did put it in there, it broke when i tried to pull it into flash. thats why i resorted to the time-tested name value pairs.

hobbis - the data i'm sending back to the php isn't huge. i'd say definitely less than a K. scripts all look fine then?

can you run me through a brief understanding of amfphp and how i can use it in this situation? don't wanna have to recode the whole dang thing but i will if i have to.

thanks guys.

steve

hobbis
07-09-2007, 01:29 PM
Just so happens I'm working on an AMFPHP project right now. Have you got your Remoting classes installed?

http://www.adobe.com/products/flashremoting/downloads/components

Personally I installed the flashremoting_comp_sourcecode.zip files and just copied the folders over to my flash installation folder.

Steps:
Upload a service php file.
You call this service from witin flash using the remoting classes.
You handle the results.

An example php service class looks like this:


<?php
class HDCGame
{
function HDCGame()
{
$dbhost = "localhost";
$dbname = "XXXXXXX";
$dbuser = "XXXXXXX";
$dbpass = "XXXXXXX";

$conn = mysql_connect($dbhost, $dbuser, $dbpass);
mysql_select_db($dbname);

$this->methodTable = array(
"insertScore" => array(
"description" => "No description given.",
"access" => "remote"
),
"getScores" => array(
"description" => "No description given.",
"access" => "remote"
),
"checkScoreAgainstScoreBoard" => array(
"description" => "No description given.",
"access" => "remote"
)
);
}

function insertScore($id, $name, $score)
{
mysql_query($str);
$str = "INSERT INTO `HDCGame` ( `id` , `Name` , `Score` ) VALUES (NULL , '" . $name . "', '" . $score . "');";
}
function getScores()
{
$str = "SELECT * FROM `HDCGame` ORDER BY Scores DESC LIMIT 0, 10;";
return mysql_query($str);
}
function checkScoreAgainstScoreBoard($score)
{
$str = "SELECT id FROM `HDCGame` WHERE Score > " . $score . " LIMIT 0, 10;";
return mysql_num_rows(mysql_query($str));
}
}
?>


An ActionScript 2.0 class would look like this:


/**
* @author Administrator
*/

import mx.remoting.*;
import mx.rpc.FaultEvent;
import mx.rpc.ResultEvent;
import mx.rpc.RelayResponder;
import mx.services.Log;
import mx.remoting.debug.NetDebug;

class CHighScores {

private var m_timeline:MovieClip;

//Service properties
private var m_service:Service;
private var m_pc:PendingCall;
private var m_logger:Log;

public function CHighScores(timeline:MovieClip)
{
m_timeline = timeline;

NetDebug.initialize();
m_logger = new Log(Log.DEBUG, "logger_cliplibrary");

}
public function IsATopScore():Void
{
m_service = new Service("http://www.XXXXXXXX.co.uk/flash/games/amfphp/gateway.php", m_logger, "HDCGame", null, null);
m_pc = m_service.checkScoreAgainstScoreBoard(CGame.GameSc oreTotalCharactersHit);
m_pc.responder = new RelayResponder(this , "highscores_Result", "highscores_Fault");
}
private function highscores_Result(re:ResultEvent):Boolean
{
if(Number(re.result) < 10)
return true;
else
return false;
}
private function highscores_Fault(re:ResultEvent):Void
{
trace("FAULT");
}

private function setTools():Void
{
}

}

Scuba_Steve
07-09-2007, 01:32 PM
hmm wanna walk me thru the AS? :) defining classes is brand new to me.

hobbis
07-09-2007, 01:53 PM
Somehwere on your timeline use something like this:

var highscores:CHighScores = new CHighScores(this);
highscores.IsATopScore();

Then in the class itself, the result handler could set a text box value:


private function highscores_Result(re:ResultEvent):Boolean
{
m_timeline.text = re.result;
}


Don't forget tp put your class in a seperate .as file CHighScores.as alongisde your fla file.

hobbis
07-09-2007, 01:59 PM
It might be a bit too much for you now :o so maybe better in the short term to fix your current code. In the long term though, you should really use amfphp or something similar.

Scuba_Steve
07-09-2007, 02:01 PM
i'd rather use amfphp if it's more efficient. problem is, i've got no clue what's wrong with my current code. :)

LOLFlash
07-09-2007, 03:09 PM
Hi Steve
I would recommend you build XML file on server side so you can debug your application. XML it is like common language for data exchange. Try getURL from flash firs and after you can use XML.load or XMLConnector

Scuba_Steve
07-10-2007, 08:34 PM
LOLFlash,

I actually wrote a separate php script that queries the data and then outputs it as XML. problem was that when i tried to then load that xml into flash, it repeatedly caused an error. seems that flash likes xml WITHOUT a doctype, while my php won't output xml unless i echo the doctype. :/

still no takers on this? $20 if you can help me sort this out. :)

LOLFlash
07-11-2007, 12:53 AM
old XML class in flash supprt XML version 1:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

but you can format XML as a string in PHP:

$myFlashOut='<?xml version="1.0" encoding="UTF-8"?>';
$myFlashOut .="<body>";
.................................................. ...........
while ($row_recordset = mysql_fetch_array($recordset)){
$myFlashOut.='<item column1=" '.$row_recordset['column1'].' " column2=" '.$row_recordset['column2].' "/>';
}

$myFlashOut.="</body>";

echo $myFlashOut;


you can get column names from PHP and loop adding attributes

Everything works fine until you have texts stored in database or special chars like -", ', <,/,& so on

now you have to do a new thread

BTW echo only full XML if you testing on local computer

Scuba_Steve
07-11-2007, 01:37 PM
if possible i would like a solution to the code i posted. i'm also looking for some education rather than just someone posting code. ;)

LOLFlash
07-11-2007, 01:49 PM
Where is your code with XML?

Scuba_Steve
07-11-2007, 02:07 PM
hmm so i'm confused. i tried what you mentioned in another thread today regarding adding "?anything=whatever" at the end of your sendAndLoad URL. Why is that necessary? If you're sending vars anyway, why must you "trick" IE into thinking you're sending variables. Does that just bypass the whole cache issue?

Adding that to my AS now results in it SORT OF saving the data, but it only saves the last row of data. How do I modify this function to only continue the loop after onLoad is successful at the end of each loop?


var continueOn:String = "Yes";
function saveChanges(){
trace("saveChanges() function triggered...");
for (var i:Number = 0; (i<prodArray.length) && (continueOn="Yes"); i++){
continueOn = "No";
saveData_lv.productNum = prodArray[i]["P/N"];
saveData_lv.newSaleType = prodArray[i]["Sale Type"];
saveData_lv.newRegPrice = prodArray[i]["R-Price"];
saveData_lv.newSalePrice = prodArray[i]["S-Price"];
saveData_lv.newUseInv = prodArray[i]["Use Inv"];
saveData_lv.newQty = prodArray[i]["Qty"];
saveData_lv.sendAndLoad("http://www.mydomain.com/path/to/my/gridsaver.php?anything=whatever", wasItSaved_lv, "POST");
wasItSaved_lv.onLoad = function(success:Boolean){
if (success){
continueOn = this.continueOn;
trace("wasItSaved_lv onLoad function triggered");
};
};
trace ("continueOn: " + continueOn);
trace ("saveData_lv.productNum =" + saveData_lv.productNum);
trace ("saveData_lv.newRegPrice = " + saveData_lv.newRegPrice);

};
setupGrid(); // need this to make sure productArray is loaded with saved data bounced back from the db.
};

LOLFlash
07-11-2007, 02:23 PM
I never did this way but you can try:

for (var i:Number = 0; (i<prodArray.length) && (continueOn="Yes"); i++){
continueOn = "No";
this[saveData_lv+i] = new LoadVars();
this[saveData_lv+i].productNum = prodArray[i]["P/N"];
this[saveData_lv+i].newSaleType = prodArray[i]["Sale Type"];
this[saveData_lv+i].newRegPrice = prodArray[i]["R-Price"];
this[saveData_lv+i].newSalePrice = prodArray[i]["S-Price"];
this[saveData_lv+i].newUseInv = prodArray[i]["Use Inv"];
this[saveData_lv+i].newQty = prodArray[i]["Qty"];
this[saveData_lv+i].sendAndLoad("http://www.mydomain.com/path/to/my/gridsaver.php?anything="+i, wasItSaved_lv, "POST");
wasItSaved_lv.onLoad = function(success:Boolean){
if (success){
continueOn = this.continueOn;
trace("wasItSaved_lv onLoad function triggered");
};
};
trace ("continueOn: " + continueOn);
trace ("saveData_lv.productNum =" + saveData_lv.productNum);
trace ("saveData_lv.newRegPrice = " + saveData_lv.newRegPrice);

};

******EDIT*******
holdon try first:

sendAndLoad("http://www.mydomain.com/path/to/my/gridsaver.php?anything="+i, wasItSaved_lv, "POST");

anothe way of doing this you can wait for server respond and send new data after ( I like it more:)



wasItSaved_lv.onLoad = function(success:Boolean){
if (success){
if(i>prodArray.length)return;
saveData_lv.productNum = prodArray[i]["P/N"];
saveData_lv.newSaleType = prodArray[i]["Sale Type"];
saveData_lv.newRegPrice = prodArray[i]["R-Price"];
saveData_lv.newSalePrice = prodArray[i]["S-Price"];
saveData_lv.newUseInv = prodArray[i]["Use Inv"];
saveData_lv.newQty = prodArray[i]["Qty"];
saveData_lv.sendAndLoad("http://www.mydomain.com/path/to/my/gridsaver.php?anything=whatever", wasItSaved_lv, "POST");
i++;
};
};



something like this

Actually you trying to write your own RDBMSResolver haw I understand

Scuba_Steve
07-11-2007, 02:31 PM
So what you've done is modified the loop so it creates a new loadVars object for each "data transfer", and adding the loop # to the end of the script URL just makes sure we avoid the caching issue?

Scuba_Steve
07-11-2007, 02:35 PM
**Error** Scene=Scene 1, layer=as, frame=20:Line 57: Syntax error.
var saveData_lv+i = new LoadVars();

Total ActionScript Errors: 1 Reported Errors: 1

how do you properly write that var? and...

**Error** Scene=Scene 1, layer=as, frame=20:Line 59: Unexpected '.' encountered
[saveData_lv+i].productNum = prodArray[i]["P/N"];


[saveData_lv+i]productNum = prodArray[i]["P/N"]; works though.

Scuba_Steve
07-11-2007, 02:49 PM
trying your EDIT didn't pan out - still only saves last row of data. i think variables in the php script are being overwritten before the script can actually finish, thus the need to KNOW when the script is done before the loop continues on with the next iteration.

LOLFlash
07-11-2007, 02:51 PM
sry I will edit my post
now I trying to give you idea

Scuba_Steve
07-11-2007, 03:40 PM
ok i can see where you're going, but how to I initiate the wasItSaved_lv to start the "loop" running? just create another loadvar to send something back to wasItSaved_lv?

and does wasItSaved_lv HAVE to receive something back from the PHP to trigger its onLoad or does the onLoad get triggered even if nothing is returned (i.e., it successfully loaded nothing)?

LOLFlash
07-11-2007, 04:11 PM
if your PHP support DOMDocument you can go with XML

Not much I can help because my PHP4 doesn’t have DOM object but I can post some code with:




$domOperation = new DOMDocument();
$xmlOperation = file_get_contents("php://input");


if ($xmlOperation == "") { die"Error processing XML");
$domOperation->loadXML($xmlOperation);

Scuba_Steve
07-11-2007, 04:14 PM
thanks for the xml suggestions. i'd like to keep my code intact as much as possible and not go the XML route at this point in time.

my current code works just fine (almost) - i just need to figure out how to delay the loop so that it doesn't continue until the php processes the information sent to it.

LOLFlash
07-11-2007, 04:27 PM
data in serial


var i:Number = 0;
function saveChanges(){
trace("saveChanges() function triggered...");

continueOn = "No";
saveData_lv.productNum = prodArray[0]["P/N"];
saveData_lv.newSaleType = prodArray[0]["Sale Type"];
saveData_lv.newRegPrice = prodArray[0]["R-Price"];
saveData_lv.newSalePrice = prodArray[0]["S-Price"];
saveData_lv.newUseInv = prodArray[0]["Use Inv"];
saveData_lv.newQty = prodArray[0]["Qty"];
saveData_lv.sendAndLoad("http://www.mydomain.com/path/to/my/gridsaver.php?anything="+i, wasItSaved_lv, "POST");
};

var wasItSaved_lv = new LoadVars();
wasItSaved_lv.onLoad = function(success:Boolean){
if (success){
if(i>prodArray.length){
i=0;
tarce("All Data Sent");
return;

}
trace(i+" Row saved on server");
saveData_lv.productNum = prodArray[i]["P/N"];
saveData_lv.newSaleType = prodArray[i]["Sale Type"];
saveData_lv.newRegPrice = prodArray[i]["R-Price"];
saveData_lv.newSalePrice = prodArray[i]["S-Price"];
saveData_lv.newUseInv = prodArray[i]["Use Inv"];
saveData_lv.newQty = prodArray[i]["Qty"];
saveData_lv.sendAndLoad("http://www.mydomain.com/path/to/my/gridsaver.php?anything="+i,wasItSaved_lv, "POST");
i++;
};
};



or if you dont need this array anymore

function saveChanges(){
trace("saveChanges() function triggered...");
continueOn = "Yes";
if(prodArray[0]==undefined){
trace("No data to save");
continueOn = "No";
return;
}

saveData_lv = prodArray.shift();
saveData_lv.sendAndLoad("http://www.mydomain.com/path/to/my/gridsaver.php?anything=whatever", wasItSaved_lv, "POST");

};

var wasItSaved_lv = new LoadVars();
wasItSaved_lv.onLoad = function(success:Boolean){
if (success){
saveChanges();
}
}



tell me if it is doesnt work