Implementing AJAX support in an MVC Framework

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

kyberfabrikken wrote:True. Except, that's called javascript -- not ajax.
The only agreed definition of "Ajax" is that it uses the XMLHttpRequest() function in Javascript. As I said above, there are a variety of ways that function is used. There are some common goals, such as avoiding page refresh, providing faster user experience, etc. but an application can use XMLHttpRequest() for all, some or none of those reasons. Likewise, an "Ajax" implementation could increase load on the server (type ahead search), or decrease load on the server (pager only needs to load part of page) -- depending on the implementation.
(#10850)
User avatar
kyberfabrikken
Forum Commoner
Posts: 84
Joined: Tue Jul 20, 2004 10:27 am

Post by kyberfabrikken »

onion2k wrote:I have no idea what point you're trying to make.
You're confusing ajax with DHTML. A very common mistake.

In traditional web applications, the browser sends a request to a server, which responds with a single HTML document. At some point, the user clicks a link, or posts a form, and a new request-response cycle commences. At each of these, an entire document is transferred and rendered by the browser. The communication uses the HTTP protocol, and the browser is always the initiator of each cycle.

Javascript is a technology, with which you can make HTML interactive, within the browser. The combination of javascript and HTML is called DHTML (Dynamic HTML).

Ajax is a way of creating web applications, in which you use javascript to communicate with the server (over HTTP), rather than let the browser do it. This allows the application to update only part of the page, rather than the entire document. While this may sound like a small thing, it radically changes how the application works, because it breaks down the traditional request-response cycle.

Just as DHTML is a superset of javascript and HTML, so is ajax a superset of DHTML and HTTP-bindings for javascript.

What you were suggestion in your previous post, was to embed the data as (server side generated) javascript code inside an HTML document. This is a traditional web application style, using DHTML. Unless you use javascript to communicate over HTTP, it can not be called ajax.

I don't think it's a bad suggestion -- in many cases, ajax may not be needed, and you can simply use DHTML. I just wish people would say DHTML, when they mean DHTML, and ajax, when they mean ajax.
User avatar
onion2k
Jedi Mod
Posts: 5263
Joined: Tue Dec 21, 2004 5:03 pm
Location: usrlab.com

Post by onion2k »

kyberfabrikken wrote:What you were suggestion in your previous post, was to embed the data as (server side generated) javascript code inside an HTML document. This is a traditional web application style, using DHTML. Unless you use javascript to communicate over HTTP, it can not be called ajax.
I was talking about the initial data loading stage. Rather than loading the AJAX application and then immediately requesting some data I said it's better to pass the application AND the data on the first request. Subsequent requests would be made via AJAX. AlexC's point that he'd need two requests (one to load the app, a second to load the initial data) is only necessary if you fail to pass the initial data to the client along with the application itself.
User avatar
kyberfabrikken
Forum Commoner
Posts: 84
Joined: Tue Jul 20, 2004 10:27 am

Post by kyberfabrikken »

onion2k wrote: I was talking about the initial data loading stage. Rather than loading the AJAX application and then immediately requesting some data I said it's better to pass the application AND the data on the first request.
Ah - I misunderstood you then. Yes, that would of course be the sane thing to do - initialise the javascript component with data on the first request.

The only case, where you wouldn't do this, is when you're using xmlhttprequest for optimisation. In an application, I am working on, a screen contains various statistics about a customer. A particular subset of this, is retrieved from an external service. Because of this, the query takes a while (About a second or so), and therefore, I use an asynchronous request to retrieve that part of the screen, so the rest of the data is available immediately. While this trick is using the same technologies as ajax does, I wouldn't call it ajax (Well, maybe I would, but that would be when explaining it to my boss ...).
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post by Kieran Huggins »

@arborint: I think I need to start drinking caffeine again - looks like my post was just a re-iteration of about 80% of your post :-) Great minds.... lol

I think the common point that we all agree on is this: build your app with good practices so it doesn't require ajax, javascript, css, etc... then you can spruce up the UI with these enhancement technologies for a better user experience. Just by following that process you will gain a clear idea of how to implement everything properly.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Kieran - I just had a cup of coffee, and I think you are simply brilliant!. :)
(#10850)
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post by Kieran Huggins »

Arborint, you got bawls!

While we're here, what does your nick mean? TreeNumber?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Kieran Huggins wrote:Arborint, you got bawls!
I prefer the Original.
(#10850)
InterHat
Forum Newbie
Posts: 7
Joined: Wed Feb 22, 2006 2:03 pm

Post by InterHat »

I'm pretty new to MVC so take my advice with a grain of salt.

Shouldn't your existing front controller just be routing and dispatching? That's all you really need for this. You shouldn't have to reload ALL of your framework, just the front controller and its routing and dispatching pieces and then the action controller. I know Zend's Front Controller doesn't have that big of a footprint.

Create a new action controller with each of your ajax processors in it as an action. In your javascript on your AJAX-enabled page just set your ajax request target to "ajax/myAjaxaction" or whatever you decide to call it. If you end up going to the URL http://my.web.site/ajax/myAjaxaction it should return your XML serialized data (depending on input of course).

Yes, you'd be reloading parts of the framework, but that's going to happen no matter what type of a controller you use, unless you decide to just hard-code in the ajax processor's file location.
User avatar
John Cartwright
Site Admin
Posts: 11470
Joined: Tue Dec 23, 2003 2:10 am
Location: Toronto
Contact:

Post by John Cartwright »

Thats essentially what arborint and Keiran were suggesting :wink:
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

How reliable is

Code: Select all

$_SERVER['HTTP_X_REQUESTED_WITH']
?
User avatar
kyberfabrikken
Forum Commoner
Posts: 84
Joined: Tue Jul 20, 2004 10:27 am

Post by kyberfabrikken »

The Ninja Space Goat wrote:How reliable is

Code: Select all

$_SERVER['HTTP_X_REQUESTED_WITH']
?
Depends on, what you mean by reliable? The client side script has to set it explicitly, so if it does, it will be set.
AlexC
Forum Commoner
Posts: 83
Joined: Mon May 22, 2006 10:03 am

Post by AlexC »

Hum, well the problem with my framework (well it's not a problem, it's how I want it but it's going to be a pain for AJAX) is that my front-controller/bootstrap does not just load one controller and that's it.

The way in which my framework works is I have 'global themes'. It will find the correct theme to load, and then load a sector map. Now a sector map tells my Theme library which controllers it should load into the different sectors (a sector is like {S1} {S2} and {SC} for the requested controller). My thinking with this is that I can have 1 main template file, and a sector map to use with it, then all the requested controller needs to worry about in terms of theme/template is just it's content, it doesn't have to worry about creating the entire template, as that is done auto-magically along with the loading of the other controllers into the other sectors.

This is probably why I'm going to have to make a light-weight AJAX specific bootstrap that only loads the requested controller, and not the other controllers a long with the global theme. Also, does the controller have to return back XML from the AJAX request?

Here is my bootstrap is any of you are interested:

Code: Select all

<?php


// ----------------------------------- \\
// @Zula Framework Bootstrap
// @License: http://www.gnu.org/copyleft/gpl.html GNU/GPL 2
// @Author: Alex Cartwright
// @Created: 11th April 2007
// ----------------------------------- \\	
	
	// Error handling and logging
	$log = Log::get_instance();	
		Registry::register( 'log', $log );
	$error = Error::get_instance();
		Registry::register( 'error', $error );		
	
	// Load settings class and load settings from default config.ini.php
	$config_file = Zula::get_dir( 'zula' ).'/config.ini.php';
	if ( !file_exists( $config_file ) || !is_readable( $config_file ) ) {
		Error::report( 'Zula configuration file does not exist', 'expected config file "'.$config_file.'" does not exist or is not readable', Error::_FATAL );
	}
	
	// We have a config file to load settings from
	$settings = new Settings();
	$settings->load( 'ini', $config_file );	
		Registry::register( 'settings', $settings );

	// Load URL aliases
	$alias_file = Zula::get_dir( 'zula' ).'/url_alias.ini.php';
	if ( file_exists( $alias_file ) && is_readable( $alias_file ) ) {
		$settings->load( 'ini', $alias_file );
	} else {
		Log::message( 'Unable to load URL alias file "'.$alias_file.'". File does not exist or is not readable', Log::L_NOTICE );
	}
	
	if ( $settings->has( 'sql/enable' ) && $settings->get( 'sql/enable' ) == true ) {		
		// Bootstrap needs to load SQL support	
		$sql = Sql::factory( $settings->get( 'sql/type' ) );			
			Registry::register( 'sql', $sql );				
		$details = $settings->get( 'sql' );		
		$sql->connect( $details['host'], $details['user'], $details['pass'], $details['database'] );
		unset( $details );
		// Load SQL settings
		$settings->load( 'sql' );
	}
		
	// Date and Input filtering
	$tmp_d = $settings->get( 'date' );
	$date = new Date( $tmp_d['format_short'], $tmp_d['format_long'], $tmp_d['use_relative'] );	
		unset( $tmp_d );	
		Registry::register( 'date', $date );		
	$input = new Input();
		Registry::register( 'input', $input );
		
	// User Group Manager (UGM) and session
	$ugmanager = new ugmanager();
		Registry::register( 'ugmanager', $ugmanager );
	$session = new Session();
		Registry::register( 'session', $session );
	
	// Mail support!
	$email = Email::factory( $settings->get( 'mail/library' ) );
		Registry::register( 'email', $email );		
	
	if ( $settings->has( 'acl/enable' ) && $settings->get( 'acl/enable' ) == true ) {
		// Enable ACL and define the ACL setting
		$settings->define_constant( 'acl/enable' );
		$acl = new Acl();
		Registry::register( 'acl', $acl );		
	}
	
	// Setup the controller
	$controller = new Controller();
		Registry::register( 'controller', $controller );
	if ( $settings->has( 'controller/use_modules' ) ) {
		// Set if the controller needs to use modules
		$controller->use_modules = $settings->get( 'controller/use_modules' );
	}
	
	// Load the router into the controller
	$router = Router::factory( $settings->get( 'url_router/type' ) );
		Registry::register( 'router', $router );
	$controller->load_router( $router );
		
	if ( $settings->has( 'theme/use_global' ) && $settings->get( 'theme/use_global' ) == true ) {
		// Using global themes, and load the correct theme for the site type
		$theme_handler = new Theme_handler();
			Registry::register( 'theme_handler', $theme_handler );
		$theme_name = $theme_handler->get_site_type_theme( Router::get_site_type() );
		// Check if the theme exists
		if ( $theme_handler->theme_exists( $theme_name ) ) {			
			// Load the new theme and load sector map
			$current_theme = new Theme( $theme_name );
				Registry::register( 'current_theme', $current_theme );				
			// Load the requested controller into SC (Sector Content)
			$current_theme->load_into_sector( 'SC', $controller->request() );			
			$current_theme->load_sector_controllers();				
			echo $current_theme->output();
		} else {
			// Nope - doesn't exist, fatal error please
			Error::report( 'Global theme is missing', 'Required theme "'.$theme_name.'" does not exist', Error::_FATAL );
		}
	} else {
		// Request and output!
		echo $controller->request();	
	}
	
?>
User avatar
kyberfabrikken
Forum Commoner
Posts: 84
Joined: Tue Jul 20, 2004 10:27 am

Post by kyberfabrikken »

AlexC wrote:This is probably why I'm going to have to make a light-weight AJAX specific bootstrap that only loads the requested controller, and not the other controllers a long with the global theme. Also, does the controller have to return back XML from the AJAX request?
Most people return JSON, rather than XML. Sometime HTML-fragments are returned. It's really up to your self.
AlexC wrote: The way in which my framework works is I have 'global themes'. It will find the correct theme to load, and then load a sector map. Now a sector map tells my Theme library which controllers it should load into the different sectors (a sector is like {S1} {S2} and {SC} for the requested controller). My thinking with this is that I can have 1 main template file, and a sector map to use with it, then all the requested controller needs to worry about in terms of theme/template is just it's content, it doesn't have to worry about creating the entire template, as that is done auto-magically along with the loading of the other controllers into the other sectors.
It sounds like you're doing a lot of things in the dispatcher, which could be deferred to the controllers. That would help you not to do a lot of work up front, which isn't needed.
Post Reply