-
9 May 2009 1:19 PM #1
Ext.Direct PHP backend
Ext.Direct PHP backend
1/25/2010
Found a few bugs when working with Ext-3.1.0 (my mistakes, not Ext's). Updated the zip file. You should be able to unzip into your examples directory (in your Ext install), and run from there.
Biggest change was due to my incorrect handling of the formHandler value required by the API. So that the API generator can detect that a particular method is a form handler, you need to add frmHandler to your method name. You can see the comments in the Profile.php class file. There was really no way that I could see of getting that info using Reflections. Someone smarter than me may have a better idea here.
Remember the main goal (at least for me) was to simply write the php code, and then have the config and api generated from the classes, instead of having to manually create and maintain them.
Demo is working with 3.1 just fine, and the demo link below has been updated to the Ext-3.1.0 version.
---------------------------------------------------------------------------------
7/11/2009
Missed a variable name change in the before and after calls.
Fixed.
7/9/2009
Fixed router for multiple arguments in actions (finally). I misunderstood what was happening there. But this should be good to go now.
Zip has been updated.
Demo here.
---------------------------------------------------------------------------------
6/17/09
Fixed router to better handle parameters
Update demo page (with form, and tree examples)
Updated the attachment with latest changes.
---------------------------------------------------------------------------------
6/5/09
Fixed router to handle parameters properly
Fixed utils to handle multiple server action classes
Updated the attachment with latest changes.
---------------------------------------------------------------------------------
Ext.Direct PHP backend
First I am not a developer, more of a guy that likes to hack around. So this is by no means and end all solution. In fact, it might just be drivel. But while working with the examples and attempting to see how I could do some comet long polling stuff, I have re-worked the PHP backend for Ext.Direct just a bit.
Might want to save your originals before unzipping.Last edited by ckr; 5 Jan 2012 at 2:58 PM. Reason: New URL - Things are working again!!
Thanks!
Chuck
-
27 May 2009 6:27 PM #2
**Updated*** So that this is more functional (the previous post is blah)
First thing to note however, is if you need a really robust solution, I would suggest looking at Tommy's solution here. So maybe this should be viewed as a "Lite" implementation.
I was looking for something a little more lightweight and less involved. So I completely rewrote the previous approach. This now supports the len, and the before and after calls. All you do is build your actions class in PHP, and plop it in the proper directory. I used this reference as a guide for working with Reflections in PHP.
The router.php is very similar to the example one provided with the release. I have added some comments, but the only portion that I really altered was the RPC portion. That has been completely redone.
baseAPI.php has been replaced by extBaseProvider.php and there is now a small additional utils.php file.
The attachment can be unzipped in the examples/direct/ directory (make a backup of yours first). Be sure to read the embedded comments for additional info. Maybe this will help someone. Just thought I would share.Thanks!
Chuck
-
31 May 2009 7:10 PM #3
-
4 Jun 2009 5:07 AM #4
Since I never heard anything on this
and now that we have some better examples with 3.0RC2, there is one change that is needed in the utils.php to support multiple server side action classes. Red code is removed, Blue is the replacement.
utils.ph - function buildAPI
This change basically flattens the array of the server classes, so that when the JSON is built, it adds the server classes as a property to the Ext.RemotingProvider actions object.Code:function buildAPI($myObj) { $myClass = new ReflectionClass($myObj); $myProp = array(); $data = array(); foreach(array_values($myClass->getProperties()) as $property) { if ($property->isPublic()) { $propName = $property->name; $propValue = $property->getValue($myObj); if ((!is_object($propValue))&&(!is_array($propValue))) { $data[$propName] = $propValue; } else { // Added this bit, in the event that this // should be an array (which I think it should be // but for now will leave as is) // if (is_object($propValue)) { $data[$propName] = getActions($propValue); } elseif (is_array($propValue)) { foreach($propValue as $obj) { $data[$propName][] = getActions($obj); if (!array_key_exists($propName, $data)) { $data[$propName] = getActions($obj); } else { $data[$propName] = array_merge($data[$propName], getActions($obj)); } } } else { die("Unexpected data type encountered..."); } } } } return $data; }
Once this change is in place, all of the new demos work.Thanks!
Chuck
-
5 Jun 2009 5:23 AM #5
See first post for new attachment with latest fixes.
Thanks!
Chuck
-
17 Jun 2009 7:57 PM #6
Another small update to the router when passing more than one parameter.
Updated the demo page here, all using this interface.
Updated the zip on the first post.Thanks!
Chuck
-
9 Jul 2009 7:27 AM #7
Multiple parameters
Multiple parameters
Hi!
I am experiencing weird behaviour using this backend.
The problem persists if I want to have more than one parameter,for example if they are two, then first parametr received have both sent values comma separated, and second is undefined..
Any ideas?
from examples.. :PHP Code:<?
class TestClass{
public function doEcho($data, $second_parameter){
return 'DATA- '.$data.' second_parameter- '.$second_parameter;
}
}
?>
POST :Code:handler: function(){ TestClass.doEcho(text.getValue(), 'value2', function(result, e){ ...
{"action":"TestClass","method":"doEcho","data":["hello","value2"],"type":"rpc","tid":2}
Response:
<b>Warning</b>: Missing argument 2 for TestClass::doEcho(), called in /router.php on line 190 and defined in <b>TestClass.php</b> on line <b>4</b><br />
<br />
<b>Notice</b>: Undefined variable: second_parameter in <b>TestClass.php</b> on line <b>5</b><br />
{"type":"rpc","tid":2,"action":"TestClass","method":"doEcho","result":"DATA- hello,value2 second_parameter- "}
Thanks in advance.
-
9 Jul 2009 11:18 AM #8
Fixed!
See first post for download of new files (router.php was the problem).Thanks!
Chuck
-
22 Aug 2009 4:25 PM #9
Your Ext.Direct PHP back-end demo is fascinating
Your Ext.Direct PHP back-end demo is fascinating
Thank you so much for this contribution. I wanted to learn from your example and saw that the TaskAction.php file inside php-lite.zip is missing these functions: updateChart, fileList, startBG and chkLoad. Anyway, I got this to work. This is what I created for startBG and chkLoad for the progress bar -- the 2 functions I was interested in.
The code for bg_task.php is as follow: installed as php/tasks/bg_task.phpPHP Code:public function startBG($dummy)
{
// generate a 20 digit task id
list($usec, $sec) = explode(' ', microtime());
$taskid = $sec . substr($usec, 2, 6) . rand(1000, 9999);
// change this to c:/<path>/... if running under windows
$statFile = '/tmp/stat-' . $taskid;
$dataFile = '/tmp/data-' . $taskid;
// set progress to 0 initially
file_put_contents($statFile, 0);
// build command string for background task
$cmd = '/usr/bin/php tasks/bg_task.php';
$cmd .= " --stat='{$statFile}' --data='{$dataFile}'";
// run the task in the background -- two examples are shown -- I used shell_exec here
## exec("{$cmd} >/dev/null 2>&1 &");
$pid = rtrim(shell_exec("nohup {$cmd} >/dev/null 2>&1 & echo $!"));
// return paths for the stat and data files
$send = "{$statFile},{$dataFile}";
return($send);
}
public function chkLoad($statFile, $dataFile)
{
while (!file_exists($statFile)) {
usleep(330000);
}
$progress = file_get_contents($statFile);
unlink($statFile);
if ($progress < 100) {
return('READ:'.$progress);
} else {
$answer = file_get_contents($dataFile);
unlink($dataFile);
return("Done: The answer to the question is {$answer}!");
}
}
Your demo helped me to understand Ext.Direct. Thank you.PHP Code:<?php
unset($statFile);
unset($dataFile);
$c = 1;
while (isset($argv[$c])) {
if (preg_match('/^--stat=/', $argv[$c])) {
list($arg, $statFile) = explode('=', $argv[$c], 2);
}
else if (preg_match('/^--data=/', $argv[$c])) {
list($arg, $dataFile) = explode('=', $argv[$c], 2);
}
++$c;
}
if (!isset($statFile) || !isset($dataFile)) {
echo "usage: {$argv[0]} --stat=<statfile> --data=<datafile>\n";
exit(1);
}
// let's simulate a long running process
usleep( 750000); file_put_contents($statFile, 9);
usleep(1500000); file_put_contents($statFile, 29);
usleep(1500000); file_put_contents($statFile, 49);
usleep(1500000); file_put_contents($statFile, 69);
usleep(1500000); file_put_contents($statFile, 89);
usleep( 750000); file_put_contents($statFile, 99);
// write the answer to the data file
file_put_contents($dataFile, 42);
// let's simulate some clean up time and state 100% afterwards
usleep(1750000); file_put_contents($statFile, 100);
?>
-
24 Aug 2009 4:51 AM #10
Hi Meroy!
Ya, I did not supply those routines mainly because you would have to make specific changes to accommodate whatever type of OS you were running on. Unfortunately my little sandbox is running Windows.
What you came up with is very close to what I threw together.
Remember this is just for testing and providing a demo. More care should be taken if implementing in a production environment. Here is my TestAction.php
And here is the bgProcess.phpCode://////////////////////////////////////////////////////////////////////////////// class TestAction { //////////////////////////////////////// // // before and after functions are not exposed to Ext.Direct, however // the router will pick up these two key named functions and // call them as thier names suggest. // // before - is called before the requested method // after - is called after the requested method // // Note: These are at the action class level. // Meaning that if either before or after are defined they will // be executed EVERYTIME ANY function within this action class is called // // By passing in the function that is to be called, you can put a test // for certain methods, in the event that you may not want to do // any pre or post processing for select methods (basically allowing // you to do pre/post processing at the Action Class level and the // the function called level. // //////////////////////////////////////// public function after($method, $data) { $myAfter = array(); // Add as needed if ($method == "multiply") { // POST processing for the multiply function // Would go in here. $myAfter['type'] = "event"; $myAfter['name'] = "message"; $myAfter['data'] = "POST Processing - AFTER Multiply"; } // POST processing for TestAction Class // Would go here return ($myAfter); } public function before($method, $data) { $myBefore = array(); // Add as needed if ($method == "multiply") { // PRE processing for the multiply function // Would go in here. $myBefore['type'] = "event"; $myBefore['name'] = "message"; $myBefore['data'] = "PRE Processing - BEFORE Multiply"; } // PRE processing for TestAction Class // Would go here return ($myBefore); } //////////////////////////////////////// // // All the functions here can be // called by Ext.Direct // //////////////////////////////////////// public function multiply($factor) { if (is_array($factor)) { $num = $factor[0]; } else { $num = $factor; } return ($num*9); } public function doEcho($data) { $pre = "ECHO:"; if (is_array($data)) { $echo = $data[0]; } else { $echo = $data; } return ($pre.$echo); } public function fileList($data) { if (is_array($data)) { $path = $data[0]; } else { $path = $data; } $list = scandir($path); return ($list); } public function startBG($data) { // Fire off the background process // and return the status handle for // future checks if (preg_match("/Win/", php_uname('s'))) { // All things required in Windows to start // a background process $UNIQUE = str_replace('.','',microtime(true)); $TITLE = "\"myProcess\" "; $SHELL = "start "; $NOWIN = "/B "; // PHP executable to run a // PHP script from the command shell $PHP = "c:/php/php.exe"; // Back Ground Process to kick off $BGP = "c:/bg-processes/bgProcess.php"; // Files that will act as named pipes // $STAT = "c:/pipes/stat-".$UNIQUE; $DATA = "c:/pipes/data-".$UNIQUE; $ARGS = $BGP." ".$STAT." ".$DATA; pclose(popen($SHELL.$TITLE.$NOWIN."\"".$PHP."\" ".$ARGS, "r")); return ("$STAT,$DATA"); } else { throw new Exception('Unexpected OS found! From loadServers method.'); } } public function chkLoad ($myStatFile, $myDataFile) { $statFile = str_replace("\"", "",$myStatFile); $dataFile = str_replace("\"", "",$myDataFile); // Allow the server process to wait for a status. // this eliminates the client from continually polling // the server, more polls by the client more resources // on the server used. // while (!file_exists($statFile)) { sleep(2); } $RP = fopen($statFile, "r"); $data = trim(fgets($RP)); fclose($RP); unlink($statFile); if ($data == "Process Completed") { $DP = fopen($dataFile, "r"); $result = trim(fgets($DP)); fclose($DP); sleep(1); unlink($dataFile); $ret = "Done:".$result; } else { $ret = "READ:".$data; } return ($ret); } public function updateChart($data) { srand(); $retValue = rand(150000, 650000); $sleepTime = rand(2, 10); sleep($sleepTime); $polled=date('g:i:s a'); $send = array('time'=>$polled, 'widgets'=>$retValue); return($send); } function getTree($id){ $out = array(); if($id == "root"){ for($i = 1; $i <= 5; ++$i){ array_push($out, array( 'id'=>'n' . $i, 'text'=>'Node ' . $i, 'leaf'=>false )); } }else if(strlen($id) == 2){ $num = substr($id, 1); for($i = 1; $i <= 5; ++$i){ array_push($out, array( 'id'=>$id . $i, 'text'=>'Node ' . $num . '.' . $i, 'leaf'=>true )); } } return $out; } }
Hope that helps!Code:$statFile = $argv[1]; $dataFile = $argv[2]; for($i=0; $i<100; $i++) { $i=$i+9; $SF = fopen($statFile, "w"); fwrite($SF, "$i\n"); fclose($SF); sleep(1); } $SF = fopen($statFile, "w"); fwrite($SF, "Process Completed\n"); fclose($SF); $DF = fopen($dataFile, "w"); fwrite($DF, "The answer to the question is 42!\n"); fclose($DF); sleep(5); exit;Thanks!
Chuck


Reply With Quote