casting from FLEX to PHP - php

AS3 code
<fx:Declarations>
<!-- this is the RemoteObject used to make the RPC calls -->
<mx:RemoteObject id="myRemote" destination="MyService" source="MyService"
endpoint="http://localhost/amfphp/gateway.php"
showBusyCursor="true"/>
</fx:Declarations>
protected function button1_clickHandler(event:MouseEvent):void
{
var aut:VOAuthor; // value object class
aut = new VOAuthor();
aut.id_aut = 3;
aut.fname_aut = "test";
aut.lname_aut = "123";
myRemote.saveData(aut);
}
Receving PHP code
public function saveData($author)
{
$mysql = mysql_connect("localhost", "mx112", "xxxxxx");
mysql_select_db("flex360");
$query = "INSERT INTO authors (fname_aut, lname_aut) VALUES ('".$author->fname_aut."', '".$author->lname_aut."')";
$result = mysql_query($query);
return $author;
}
<?php
class VOAuthor {
public $id_aut;
public $fname_aut;
public $lname_aut;
var $_explicitType="org.corlan.VOAuthor";}
?>
Flex network monitor response : Raw view
{lname_aut=123, _explicitType=org.corlan.VOAuthor, fname_aut=test, id_aut=3}
but If I do this at the end of the php code
return $author->lname_aut;
network monitor response is NULL
so the problem is I can print the array but how to cast tht array to a known php type ?
After 5 days I finnaly figured out flex and mysql using amfphp any one please help ?

if you are using amfphp and Flash you have to register your VOs:
import org.corlan.VOAuthor;
// ...
registerClassAlias("org.corlan.VOAuthor", VOAuthor);
only then does php recognize the objects you're sending it from ActionScript.

Yes you need to register your class, and an alternative is to use the metadata tag in the Flex VO declaration.
package VO
{
[RemoteClass(alias="org.corlan.VOAuthor")]
public class VOAuthor
{
private var id_aut : int;
public var fname_aut : String;
public var lname_aut : String;
...
Hope that helps,
Roger.
PS. A more detailed explanation (that helped me) can be found here: http://www.brentknigge.com/?q=node/499

Related

PHP Soap Client does not send all object properties in a webservice call

I try to implement a webservice Client using php and got stuck...
I'm using an existing webservice called metadataservice with a known wsdl.
I'll use wsdl2phpgenerator to create the php classes for the datatypes and the Service itself.
Using one of the Webservice Methods (addMetadataToObject), I have to send an Array of objects to the Server.
There is a base class:
class AssetInfo
{
public $dataFieldId = null;
public $dataFieldName = null;
public $dataFieldTagName = null;
public function __construct($dataFieldId, $dataFieldName, $dataFieldTagName)
{
$this->dataFieldId = $dataFieldId;
$this->dataFieldName = $dataFieldName;
$this->dataFieldTagName = $dataFieldTagName;
}
}
and a derived class Holding string values (there are also other derived classes for Longs etc.):
class StringAssetInfo extends AssetInfo
{
public $value = null;
public function __construct($dataFieldId, $dataFieldName,$dataFieldTagName, $value)
{
parent::__construct($dataFieldId, $dataFieldName, $dataFieldTagName);
$this->value = $value;
}
}
For the call of Metadataservice->addMetadataToObject there is also a addMetadataToObject defined:
class addMetadataToObject
{
public $objectId = null;
public $objectType = null;
public $assetInfos = null;
public function __construct($objectId, $objectType)
{
$this->objectId = $objectId;
$this->objectType = $objectType;
}
}
The property $assetInfos should hold an Array of AssetInfo objects. wdsl2phpgenerator creates a class for my MetadataService which is derived from SoapClient. This class provides all the avialable Methods for this Service. Here I only show the addMetadataToObject Method:
public function addMetadataToObject(addMetadataToObject $parameters)
{
return $this->__soapCall('addMetadataToObject', array($parameters));
}
My Code does:
// Define the Data
$ServiceOptions = [];
$AssetInfos = [];
$AssetInfo = new StringAssetInfo(2, "TitleName", "TitleName","New Title Name);
array_push($AssetInfos, $AssetInfo);
// Create the Service
$Service = new MetadataService($ServiceOptions, getServiceWSDL($Options, "MetadataService"));
$Service->__setSoapHeaders(getGalaxySoapHeader($Options));
$NewMetaData = new addMetadataToObject(61755, "ASSET");
$NewMetaData->assetInfos = $AssetInfos;
// Call the Service
$failedAssets = $Service->addMetadataToObject($NewMetaData);
The call throws a Soap Exception that a value could not be extracted. Which makes me wonder. I started to monitor the traffic to the Soap Server using wireshark and yes....there is no value anymore as defined in the StringAsset Info Class...Here is the Soap Body shown by wireshark:
<SOAP-ENV:Body>
<ns1:addMetadataToObject>
<objectId>61755</objectId>
<objectType>ASSET</objectType>
<assetInfos>
<dataFieldId>2</dataFieldId>
<dataFieldName>TitleName</dataFieldName>
<dataFieldTagName>TitleName</dataFieldTagName>
</assetInfos>
</ns1:addMetadataToObject>
Id</SOAP-ENV:Body>
I would expect a tag New Title Name. But ist gone. When I checked the $NewMetaData object in my Code or the $Parameter object in $Service->addMetadataToObject I can see that the property "Value" is defined and set.
For me it seems, that the call to
return $this->__soapCall('addMetadataToObject', array($parameters));
only accepts the properties of the base class AssetInfo but not the properties from the derived class StringAssetInfo.
I also changed the Code to use an Array (instead of an object) for $AssetInfo:
$AssetInfo = array("dataFieldId"=>2, "dataFieldName"=>"TitleName","dataFieldTagName"=>"TitleName, "value"=>"New Title Name");
But without any change. It seems that we have here some Kind of runtime type conversion or type alignment but I can't see the reason of this. I'm still new to webservices at all and also on php (however I have to use both for the Moment:-)
Can anybody comment or give me a hint what's happening here?
I was able to realize it by using Arrays and soapvars, Please note my comments in the code:
$ServiceOptions = [];
$AssetInfos = [];
// I have to use an Array because the Server depends on the order of the properties. I wasn't able to define expected order using the existing objects but with arrays
$AssetInfo = array("dataFieldId"=>2, "dataFieldName"=>"TitleName","dataFieldTagName"=>"TitleName, "value"=>"New Title Name");
// instead of pushing the Array directly, I create an instance of an SoapVar, pass the Array as data and set the Encoding, the expected type and the Namespace uri
array_push($AssetInfos, new SoapVar($AssetInfo, SOAP_ENC_OBJECT, "StringAssetInfo", "http://metadataservice.services.provider.com"));
array_push($AssetInfos, $AssetInfo);
// Create the Service
$Service = new MetadataService($ServiceOptions, getServiceWSDL($Options, "MetadataService"));
$Service->__setSoapHeaders(getGalaxySoapHeader($Options));
$NewMetaData = new addMetadataToObject(61755, "ASSET");
$NewMetaData->assetInfos = $AssetInfos;
// Call the Service
$failedAssets = $Service->addMetadataToObject($NewMetaData);
This produced the expected Output in the Soap Body (and also added some namespaces to the Soap envelope
<SOAP-ENV:Body>
<ns1:addMetadataToObject>
<objectId>61755</objectId>
<objectType>ASSET</objectType>
<assetInfos xsi:type="ns1:StringAssetInfo">
<dataFieldId>2</dataFieldId>
<dataFieldName>TitleName</dataFieldName>
<dataFieldTagName>TitleName</dataFieldTagName>
<value>New Titel Name 1146</value>
</assetInfos>
</ns1:addMetadataToObject>
</SOAP-ENV:Body>

Using custom class to handle database inquiries in AS3

I recently started delving into custom classes in AS3 (to hone my best-practices coding habits), and wanted to create a database class that allows a user to first instantiate a class that contains all the information necessary for methods within the class to add, delete, modify (etc) rows in a MySQL table (via PHP). Of course, this involves using URLRequest, URLLoader and so forth. My question is whether anyone as figured a way how to return data from a method specifically containing that var data without relying upon the method essentially dispatching an event (then having to create a listener rather than having that built into the class). For example,
var myDB:dataBase = new dataBase("dbase","table","username","pword");
//this creates an instance of a database class with methods like:
trace(myDB.fetch(1)); //gets first row of table as a delimited string
OR
if (myDB.delete(1)) {}
//returns Boolean true if delete of row 1 was successful
I found the answer below that contained a way to create a class that returns an event:
Combining URLRequest, URLLoader and Complete Event Listener In Actionscript 3.0?
but I want the method to return a string containing data from the database or a boolean confirmation, not to dispatch an event listener. Here is an example of the class I made:
package com.customClasses {
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLVariables;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequestMethod;
import fl.events.DataChangeEvent;
import flash.events.Event
public class dataBase {
public var dbs:String = "";
public var usr:String = "";
public var pwd:String = "";
public var tab:String = "";
var returnData:String = "";
// Constructor
public function dataBase(dbs:String, usr:String, pwd:String, tab:String) {
this.dbs = dbs;
this.usr = usr;
this.pwd = pwd;
this.tab = tab;
}
public function fetch(idn:uint, par:String):String {
var returnData:String = "blank";
var vUrlReq:URLRequest = new URLRequest ("dBase.php");
var vUrlVars:URLVariables = new URLVariables();
function onLoadVarsComplete(event:Event): void {
//retrieve success variable from our PHP script:
if(event.target.data.msg == "success") {
var rawData:URLVariables = new URLVariables( event.target.data );
returnData = rawData.fromPHP;
} else {
returnData = "failed!";
}
}
vUrlReq.method = URLRequestMethod.POST;
vUrlVars.dir=dbs; // name of table affected
vUrlVars.alpha=usr; // username
vUrlVars.beta=pwd; // password
vUrlVars.dbase=tab; // name of table affected
vUrlVars.func="fetch"; // function for php script to use
vUrlVars.idnum=idn; //if >0 search for record with that id
vUrlReq.data = vUrlVars;
var vLoader:URLLoader = new URLLoader (vUrlReq);
vLoader.addEventListener("complete", onLoadVarsComplete);
vLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
vLoader.load(vUrlReq);
return (returnData);
}
returnData returns "blank"... so I realize my method is not working as intended. I also realize there my be some scope issues with the returnData string, and that I am using a nested function (probably a no-no). Otherwise, any thoughts?
To do what you want, you can use a callback function or a DataEvent listener, like this :
DB.as :
package {
import flash.net.*;
import flash.events.*;
public class DB extends EventDispatcher {
public static const DATA_LOADED = 'data_loaded';
public function DB() {
}
public function getDataUsingDataEvent(file_path:String):void {
var url_loader:URLLoader = new URLLoader();
url_loader.addEventListener(
Event.COMPLETE,
function(e:Event):void
{
var event:DataEvent = new DataEvent(DATA_LOADED, true, false, url_loader.data);
dispatchEvent(event);
}
)
url_loader.load(new URLRequest(file_path));
}
public function getDataUsingCallback(file_path:String, callback:Function):void {
var url_loader:URLLoader = new URLLoader();
url_loader.addEventListener(
Event.COMPLETE,
function(e:Event):void
{
callback(url_loader.data);
}
)
url_loader.load(new URLRequest(file_path));
}
}
}
And then :
var db:DB = new DB();
db.addEventListener(
DB.DATA_LOADED,
function(event:DataEvent):void {
trace(event.data);
}
)
db.getDataUsingDataEvent('file_path');
db.getDataUsingCallback(
'file_path',
function(data:String):void {
trace(data);
}
)
Hope that can help.
As you've stated it, this can't be done in AS3. You cannot wait for an asynchronous operation (such as URLLoader/load()) before returning the function and continuing script execution.
What you can do, if you'd prefer not to use addEventListener() so much, is pass through callbacks, or implement method chaining of promises. These patterns are not necessarily better than using events, and have their own problems, but let you write code that is arguably more readable as a sequence. These patterns are common in Javascript (which has the same asynchronous behavior as ActionScript), for example jQuery. Beware of "callback hell" and "train wrecks". These techniques aim to make things simpler to write but sometimes make things more error prone.

php and high latency

I have a php file that previously used to write xml data with tags. Now I'm trying to make it a little remoteobject based. So instead of writing xml I'm trying to return a class object that consists some big multidimensional array. The problem is it is causing a high latency. I'm not sure if it's my php file that is causing latency problem.
My php code :
class output{
public $grid;
public $week;
public $name;
var $_explicitType = "org.test.output";
}
class manager1{
function init($params,$arrayOut)
{
$action = $params[0];
switch ($action)
{
case "reload": return $this->Reload($arrayOut);break;
default:return $this->form($arrayOut);
}
}
private function Reload($arrayOut)
{
$this->getSlice();
$arrayOut->grid = $this->gridValue();
$arrayOut->week = 'no data';
return $arrayOut;
}
private function form($arrayOut)
{
$arrayOut->grid = $this->gridValue();
$arrayOut->week= $this->getAllWeek($this->ThisYear);
return $arrayOut;
}
}
AS-3 code calling php function:
private function init():void{
var _amf:RemoteObject = new RemoteObject();
var params:Array = new Array(); //parameters array
params.push("default");
var arrayOut:output = new output();//strongly typed class
_amf.destination = "dummyDestination";
_amf.endpoint = "http://insight2.ultralysis.com/Amfhp/Amfphp/"; //amfphp home directory
_amf.source = "manager1"; //the php class which will be called
_amf.addEventListener(ResultEvent.Result, handleResult);
_amf.init(params,arrayOut);
}
private function handleResult(event:ResultEvent):void
{
datagrid.dataProvider = event.result.grid;
}
And there is also a class named output in my application:
package org.test{
public class output
{
public var grid:Array;
public var week:Array;
}
}
I'm using this to pass value to flex remoteobject using amfphp.
Actually, it's fairly easy to figure out.
You can use the Network Monitor that is part of Flash Builder. It shows the Request Time and the Response Time, so you can get a pretty good idea if the issue is with the PHP side or the Flex side. You can also see the size of the response.
Be aware that Remote Objects mixed with Multidimentional arrays can be larger than you think, but again the Network Monitor will help you figure out that.

Change default REST response to be only XML in Zend

I've worked on this code base and it responds with html when i access a site www.site.com/version/
However, If i access www.site.com/version?format=xml, it displays output in xml.
How can I change the Zend code to ONLY output in XML irrespective of the format request? Yeah, i'm new to Zend coding...)
My code is exactly what Chris has ( http://www.chrisdanielson.com/2009/09/02/creating-a-php-rest-api-using-the-zend-framework/ ) :
class VersionController extends Zend_Rest_Controller
{
public function init()
{
$bootstrap = $this->getInvokeArg('bootstrap');
$options = $bootstrap->getOption('resources');
$contextSwitch = $this->_helper->getHelper('contextSwitch');
$contextSwitch->addActionContext('index', array('xml','json'))->initContext();
//$this->_helper->viewRenderer->setNeverRender();
$this->view->success = "true";
$this->view->version = "1.0";
}
...
...
You can force the context to use XML only by following code:
$this->_helper->contextSwitch()->initContext('xml');
Refer link:
http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.contextswitch.initcontext

Send xml from ActionScript to PHP

I have values inside an XMLList in Actionscript. Need to send these values to the DB and update it.
My actionscript code is as follows:
public static function saveUserPermList():void {
var ht:HTTPService = new HTTPService();
ht.url = Config.getServerURL();
ht.method = URLRequestMethod.POST;
//ht.resultFormat = "e4x";
ht.contentType = "text/xml";
ht.request["action"] = "saveUserPermListXML";
ht.request["pdata"] = Application.application.userPermListModel.toString();
ht.addEventListener(ResultEvent.RESULT,AdminUserList.saveUserPermListResult);
ht.send();
}
public static function saveUserPermListResult(e:ResultEvent):void {
trace(e);
}
How can I send the XMLList data to PHP? Should I add a toString() to it?
Also what should be the contentType in Flex.
How can I catch this inside PHP, pl let me know, trying to use, this way,
if($user -> isAllowedAccess()) {
header("Content-type:text/xml");
$postedData = $_POST["pdata"];
// $xmldoc = simplexml_load_string($POST['pdata']);
// echo($xmldoc);
}
No luck. Pl let me know.
The method property of HTTPService should probably be "POST", and the contentType for the request itself should probably be "application/x-www-form-urlencoded".
On the PHP side, $_POST["pdata"] would then be a string containing XML markup. You could either save that in a database directly, or first parse it into XML (via SimpleXML or DOMDocument) and do something with the contained data.
PS: I've just found this answer that seems to shed some light on the internal behavior of the HTTPService class.

Categories