forked from bcit-ci/CodeIgniter
-
Notifications
You must be signed in to change notification settings - Fork 0
Amfphp and CI
Derek Jones edited this page Jul 5, 2012
·
10 revisions
Category:Config | Category:Config::Integration | Category:Config::Community
This is an easy way to integrate Amfphp with CI, without the need to modify core libraries by using hooks. This article is an expansion of my forum post here .
Note: see this later post for clarifications on some parts of Noinx's setup
It seems that CI will output headers even if no views are defined, causing errors. The following prevents output from displaying when using Amfphp, but allows output for standard page display.
-
Enable hooks in config.php
-
In application/config, add this to hooks.php:
$hook['display_override'] = array(
'class' => 'Amfphp',
'function' => 'output',
'filename' => 'amfphp.php',
'filepath' => 'hooks'
);
- Create a new file in application/hooks called amfphp.php and add this text:
<?php
class Amfphp
{
var $ci;
function output()
{
if(!defined('AMFPHP'))
{
$this->ci =& get_instance();
$this->ci->output->_display($this->ci->output->get_output());
}
}
}
?>
- Create an Amfphp gateway service. This code assumes that your Code Igniter index.php file and the Amfphp gateway folder are in the main web root directory. Optional vars are sent to $_POST, thanks frenzal.
<?php
class action
{
function execute($path, $vars=false)
{
define('AMFPHP', 1);
global $value;
if($vars AND is_array($vars)){
// Convert vars to POST data
$_POST = $vars;
}
$_SERVER['PATH_INFO'] = '/'.$path;
$_SERVER['QUERY_STRING'] = '/'.$path;
$_SERVER['REQUEST_URI'] = '/'.$path;
require_once('../../../index.php');
return $value;
}
}
?>
- Create your controllers. It seems that using hooks solved the problem with loading libraries in the controller functions.
<?php
if (!defined('AMFPHP')) exit('No direct script access allowed');
class Cont extends Controller {
function Cont()
{
parent::Controller();
}
function func()
{
global $value;
$test = 'Some Stuff';
$value = $test; // $value can be any data type. If it's an array, it should be sent back as an array collection.
}
}
?>
- Setup a remote event Flex or Flash to call your controllers. The following is Flex 3 Actionscript code. Create a file called RemoteEvent.as in src/events directory.
package events
{
import flash.events.Event;
public class RemoteEvent extends Event
{
public var data:*;
public function RemoteEvent(type:String, data:*)
{
super(type);
this.data = data;
}
}
}
- Create an event dispatcher to send the request to Amfphp which calls your CI controller and function. There is probably a better way to implement this, but it works. This is also Actionscript code. Create this file as Remote.as in src/events directory in Flex 3.
package events
{
import flash.events.EventDispatcher;
import mx.collections.ArrayCollection;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.mxml.RemoteObject;
public class Remote extends EventDispatcher
{
// Debug
private var debug:Boolean = false;
// Event names
private var successEventName:String;
private var faultEventName:String;
// Remote Object
private var ro:RemoteObject = new RemoteObject("amfphp");
// Path
private var pathItems:ArrayCollection;
// Constructor
public function Remote(success:Function = null, fault:Function = null) {
// Create random name for event dispatch
var time:Date = new Date();
var eventName:String = time.getTime().toString() + "_" + Math.round(Math.random()*99999) + 1;
// Set success remote events
var successName:String = "success_" + eventName;
this.successEventName = successName;
this.addEventListener(successName, success);
ro.addEventListener(ResultEvent.RESULT, this.onSuccess);
// Set fault remote events
var faultName:String = "fault_" + eventName;
ro.addEventListener(FaultEvent.FAULT, this.onFault);
if(fault != null) {
this.faultEventName = faultName;
this.addEventListener(faultName, fault);
}
}
// Build path
public function addPath(item:String):void {
if(this.pathItems == null) {
this.pathItems = new ArrayCollection;
}
this.pathItems.addItem(item);
}
// Send remote request
public function send(path:String = "", obj:* = null, showBusyCursor:Boolean = true):void {
ro.source = "ci.action";
ro.showBusyCursor = showBusyCursor;
if(this.pathItems != null) {
// Use path array
var newPath:String = this.pathItems.source.join("/");
this.ro.execute(newPath, obj);
}
else {
this.ro.execute(path, obj);
}
}
// Success handler
private function onSuccess(event:ResultEvent):void {
var ci:Object = new Object();
ci = event.result;
this.dispatchEvent(new RemoteEvent(this.successEventName, ci));
}
// Fault handler
private function onFault(event:*):void {
if(this.debug == true) {
trace("AmfPHP Fault");
}
trace(event.message);
if(this.faultEventName != null) {
this.dispatchEvent(new RemoteEvent(this.faultEventName, event.message));
}
}
}
}
- Make sure you have a file called services-config.xml in the src directory in Flex 3. Replace the codeigniger.com address in endpoint with your domain name and path to gateway.php. It should look like this:
<?xml version="1.0" encoding="UTF-8"?>
<services-config>
<services>
<service id="amfphp-flashremoting-service"
class="flex.messaging.services.RemotingService"
messageTypes="flex.messaging.messages.RemotingMessage">
<destination id="amfphp">
<channels>
<channel ref="my-amfphp"/>
</channels>
<properties>
<source>*</source>
</properties>
</destination>
</service>
</services>
<channels>
<channel-definition id="my-amfphp" class="mx.messaging.channels.AMFChannel">
<endpoint uri="http://www.codeigniger.com/gateway/gateway.php" class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>
</channels>
</services-config>
- Go to the Project menu > Properties > Flex Compiler. Add this to the Additional compiler arguments:
-services "services-config.xml"
- Create the mxml file to test this code.
<!--Scripts-->
<mx:Script source="as/code.as"/>
<mx:Button x="159" y="25" label="Button" click="{this.remoteTest();}"/>
<mx:Label x="79" y="75" text="{this.strRemoteTest}"/>
- Create the Actionscript file to initiate the call to your CI code.
import events.RemoteEvent;
import events.Remote;
// Send request
private function remoteTest():void {
// Instantiate a new variable as type Remote and pass the functions that will handle the success or fault events that will be generated. The second argument is optional.
var test:Remote = new Remote(this.onRemoteTest, this.RemoteTestFault);
// This will send the request to a controller named cont and a function within that controller named func. An optional second parameter may contain an array or other object.
test.send('cont/func');
// The path may be built instead, for easy variable use.
// test.addPath('user/login');
// test.addPath('fred');
// test.addPath('password');
// test.send();
// This will send user/login/fred/password to CI's URI. The username may be accessed by using $this->uri->segment(3); (Note: You may want to encrypt login data before sending).
}
// This var's data will display in a label when the button is pressed.
[Bindable]
private var strRemoteTest:String;
// On success the vars is populated with data from CI via Amfphp
private function onRemoteTest(event:RemoteEvent):void {
this.strRemoteTest = String(event.data);
}
// This function is triggered when a problem is occurs.
private function RemoteTestFault(event:RemoteEvent):void {
trace(event.data);
}
Author: Noinx