|
FAQ
Frequently Asked Questions
What is SabreAMFSabreAMF allows you to create flash remoting (a.k.a. AMF-) webservices using PHP. These services can be used by flash or flex as a replacement for for example XML documents or 'sendAndLoad'. The main advantages are that it is native to flash and has a relatively easy API (you don't have to parse xml documents), and that its often faster to load. Because of the binary format the HTTP packages are also often smaller, especially for bigger chunks of data. How does SabreAMF compare to WebOrb for PHP or AMFPHPIf you are a beginner or you are looking for a very complete out of the box AMF solution, i would definitely advice to use AMFPHP or WebOrb. Its pretty much install-and-go with those products. If you are looking for a more low-level library to parse AMF data and requests, or you want to integrate flash remoting into your existing (webservices-)framework SabreAMF might be a better choice. It is written to not pollute the global namespace, apply 'proper' OOP and run in PHP 5.2 strict mode. Additionally, the package also contains an AMF client; which can be useful to test other services or poke through the alleged security of binary formats and crossdomain.xml. What doesn't it do
Can I use SabreAMF with PHP 5.1Yes, the only reason PHP5.2 is a requirement, is for the new DateTime object. If you create a class like this: <?php
class DateTime {
private $time;
function __construct($datestring) {
$this->time = strtotime($datestring);
}
function format($dateformat) {
return date($dateformat,$this->time);
}
}
?> It will work just fine in PHP 5.1. PHP 5.0 is not supported and its use is discouraged in general because its kinda slow and buggy. Where do I start?If you want to create an amf gateway, check out the CallbackServer documentation. The tgz package contains an examples folder, which should help you get started writing a server or client. Also, some more advanced examples can be found on the semi-offical blog How can I help out?
|
Sign in to add a comment
Can you give a little sample on how to use the DateTime? object with sabreamf. Mappings are perfect(flash/flex vo has a Date member) but the php class receives an empty date instance.
Hi Stoica,
Are you receiving an empty date class from Flex? Sounds like a bug..
Please record your session with charles, and open a bug in the issue tracker (http://code.google.com/p/sabreamf/issues/list)
Evert
Its not a problem after all, its just a simple PHP thing :), the data that is returned to flash, must not be strings (i use PDO fetch class to create objects from database, something like a mini orm(no relations whatsoever), but PDO makes all fields strings) cause sabreamf has no clue on how to map them and this is normal (no strict type). I've fixed it by inspecting the database table columns and then use php functions intval/floatval/date_create.
http://paste2.org/p/52736
For all the people wanting to integrate flash player technologies with zend framework, here is how i do it and it works perfectly:
I currently use SabreAMF with Zend Framework because is php5 and it is compatible with zend framework naming conventions.
First, you must add SabreAMF to your library path (or php include path) then here is a sample controller.
You can as easily switch to AMFPHP, on thing to notice is that the amf services are not zend controllers but plain old php objects, so in your mvc layout i introduced also a services holder
example module:
module: - models - views - controllers - services
As you can see i also use doctrine and i return strongly typed objects to flex, you can go further and implement VO's (follow either sabreamf or amfphp docs) but i just did not need that:
class AmfController extends Zend_Controller_Action { protected $_namespace = 'AmfController'; public function preDispatch() { $this->_helper->layout->disableLayout(); $this->_helper->viewRenderer->setNoRender(); } public function indexAction() { //$this->runAMFPHPServer(); $this->runSabreAMFServer(); } private function runSabreAMFServer() { $server = new SabreAMF_CallbackServer(); $server->onInvokeService = array($this, 'onCallBack'); SabreAMF_ClassMapper::$onGetLocalClass = array($this, 'onGetLocalClass'); SabreAMF_ClassMapper::$onGetRemoteClass = array($this, 'onGetRemoteClass'); $server->exec(); } public function onGetLocalClass($class) { return $class; } public function onGetRemoteClass($class) { return $class; } /* private function runAMFPHPServer() { $paths = $this->getPaths(); Zend_Session::start(); require_once "amfphp/core/amf/app/Gateway.php"; $server = new Gateway(); $server->setClassPath($paths['services']); $server->setClassMappingsPath($paths['models']); $server->setCharsetHandler('utf8_decode', 'ISO-8859-1', 'ISO-8859-1'); $server->setErrorHandling(E_ALL ^ E_NOTICE); $server->enableGzipCompression(25*1024); //$server->disableDebug(); $server->setLooseMode(true); $server->service(); } */ public function onCallBack($service, $method, $data) { $paths = $this->getPaths(); $pos = strrpos($service, '.'); $serviceName = ''; if($pos === FALSE) $serviceName = $service; else $serviceName = substr($service, $pos + 1); $servicePath = $paths['services'] . $service . '.php'; if(!file_exists($servicePath)) throw new Exception('Inexisting service(files does not exist) '.$servicePath.' for service '.$service.' '.$method); require_once $servicePath; if(!class_exists($serviceName)) throw new Exception('Undefined service(class does not exist) '.$serviceName); $instance = new $serviceName; if(!is_callable(array($instance, $method))) throw new Exception('Inexisting service method '.$method); $result = call_user_func_array( array($instance, $method), array($this, $data[0]) ); if($result instanceof Doctrine_Record) { $result = $this->typeCast($result); } elseif ($result instanceof Doctrine_Collection) { $retval = array(); $size = count($result); for($i=0;$i<$size;$i++) { $retval[$i] = $this->typeCast($result[$i]); } $result = $retval; } return $result; } private function getPaths() { $moduleName = $this->_getParam('name', 'fms'); $front = Zend_Controller_Front::getInstance(); $moduleControllerDirectoryName = $front->getModuleControllerDirectoryName(); $controllerDirectory = $front->getControllerDirectory($moduleName); return array( 'services' => rtrim($controllerDirectory, $moduleControllerDirectoryName) . 'services/', 'models' => rtrim($controllerDirectory, $moduleControllerDirectoryName) . 'models/' ); } private function typeCast(Doctrine_Record $result) { $columns = $result->getTable()->getColumns(); $relations = $result->getTable()->getRelations(); foreach($columns as $cn => $cp) { $to_type = 'to_'.$cp['type']; $result->$cn = $this->$to_type($result->$cn); } return $result; } private function to_string($val) { return (string)$val; } private function to_varchar($val) { return (string)$val; } private function to_boolean($val) { return $val === 1 ? TRUE : FALSE; } private function to_integer($val) { return intval($val); } private function to_decimal($val) { return floatval($val); } private function to_float($val) { return floatval($val); } private function to_timestamp($val) { return date_create($val); } private function to_time($val) { return date_create($val); } private function to_date($val) { return date_create($val); } } ?>One could implement plugins based on the content type and transform controllers directly into services (like for example ajax actions are, when they return json-ized data), but my current knowledge of zend framework is missing that part ... soon.