Exciting new model architecture
AX Framework brings along some very exciting new concepts, that might change
the way you think web application development forever.
With AX Framework you no longer think of your application in endless complex-logic view layouts, but in
seperate layers of object representation, that will make your source code lean, clean, compact,
efficient and rock-solid.
Schematic overview
With all being windowed content, you will rethink intranet development.
You will concept your project in dynamic, data-object related pages and multiforms.

Here is how unaltered page calls are handled with ax:
- A Page
is requested by the client; either the user has clicked a) on a link on another page,
b) on a link on his desktop, or c) he chose an entry point from the the menusystem.
In most cases, this call typically comes with an id, that refers to the
specified dataset - the so-called DataOjbect-Id - which is the primary id of the
primary data table.
- The rendered HTML content of the page is shown within the newly created
ProcessLayer
(=UI-window)
In most common cases this ProcessLayer will just hold a placeholder for an
MultiForm,
which will be initialized by ProcessLayer's JavaScript now.
- The MultiForm
(client) gets initialized and asks the
DataProcessor
(server) for wanted layout and data.
- The DataProcessor
(server) instanciates the necessary
DataObject(s)
and replies with form layout (XML) and the dataset in JSON format.
- The form can now be presented to user
Note to MVC specialists
Please note, that this is not a traditional MVC setup. While it might be true, that our DataObject somewhat
corresponds to what is commonly known as «Model» and our DataProcessor might correspond to
being a «Controller», nonetheless our Page, MultiForm do not really correspond
to being a classic «View».
We would still recommend to get a fresh view on our Model independently to all previous layouts.
Module/Project structure
Here's a very run down example how a project (here: a simple carsharing module) could be built up within ax:
Please keep in mind ax actually built for high comlex projects more than simple three table layouts.
Example
Let's imagine we have a bunch of cars at our disposal, which are being rented out to people we know.
We would like to keep track of information about: Cars, Persons and Bookings.
|
Tables
For this we will initialize three tables. Let's use "Demo Carpool" as our project/module name.
- democarpool_cars
- democarpool_persons
- democarpool_bookings
|
Pages
- Cars
let's create a page like this to edit our car data and keep track of bookings
- Persons
let's create a page like this to edit the persons
|
Forms
for these pages we will lay out two forms:
|
AX Entities
So for our project we will need the following entities:
- Carpool
- do
- Car.php
- Person.php
- Booking.php
- dp
- forms
- pages
- sopts
<?php
class Car extends AX_DataObject {
public function create() {
$this->data = $this->db->getObjectByTablename("democarpool_cars");
}
public function load() {
$this->data = $this->db->fetchRowBySQL("SELECT * FROM democarpool_cars WHERE id = $this->id");
}
public function nestBookings() {
$this->data->Bookings = $this->extendBySQL("SELECT id FROM democarpool_bookings WHERE Car = " . $this->id, "Booking");
foreach($this->data->Bookings as $myBooking) {
$myBooking->load();
$myBooking->nestPerson();
$myBooking->prepare();
}
}
public function prepare() {
$this->data->_Cartype = $this->data->Cartype;
$this->data->_Info = $this->data->Info;
$this->data->_text = $this->data->Cartype;
$this->data->_html = $this->data->_text;
}
public function save() {
if(isset($this->data->Bookings)) {
$this->stdSaveChilds((object) array(
"table" => "democontractor_bookings",
"data" => $this->data->Bookings,
"childDO" => "Booking",
"childCond" => (object) array(
"Car" => $this->id
),
"prepareRows" => function($myDataRow,$mainId) {
$myDataRow->Car = $mainId;
return $myDataRow;
}
));
}
$this->stdSaveMain((object) array (
"table" => "democarpool_cars"
));
}
public function delete() {
; // currently no delete of cars permitted
}
public function findByText($searchVal) {
$sql = "SELECT id FROM democarpool_cars WHERE (Cartype LIKE '$searchVal%' OR License LIKE '$searchVal%')";
return $this->db->fetchColBySQL($sql);
}
}
<?php
class Person extends AX_DataObject {
public function create() {
$this->data = $this->db->getObjectByTablename("democarpool_persons");
}
public function load() {
$this->data = $this->db->fetchRowBySQL("SELECT * FROM democarpool_persons WHERE id = $this->id");
}
public function nestBookings() {
$this->data->Bookings = $this->extendBySQL("SELECT id FROM democarpool_bookings WHERE Person = " . $this->id, "Booking");
foreach($this->data->Bookings as $myBooking) {
$myBooking->load();
$myBooking->nestCar();
$myBooking->prepare();
}
}
public function prepare() {
$this->data->_Name = $this->data->Name;
$this->data->_LastBooking = '';
$this->data->_text = $this->data->Name;
$this->data->_html = $this->data->_text;
}
public function save() {
$this->stdSaveMain((object) array (
"table" => "democarpool_persons"
));
}
public function delete() {
$Bookings = $this->db->fetchRowsBySQL("SELECT * FROM carsharing_bookings WHERE Person = " . $this->id);
if(count($Bookings)>0) {
$this->addError("Person " . $this->data->_text . " is linked in Bookings and can therefore not be deleted");
return false;
}
$this->db->performSQLString("DELETE FROM democarpool_persons WHERE id = " . $this->id);
}
public function findByText($searchVal) {
$sql = "SELECT id FROM democarpool_persons WHERE (Name LIKE '$searchVal%' OR Info LIKE '$searchVal%')";
return $this->db->fetchColBySQL($sql);
}
}
<?php
class Booking extends AX_DataObject {
public function create() {
$this->data = $this->db->getObjectByTablename("democarpool_bookings");
}
public function load() {
$this->data = $this->db->fetchRowBySQL("SELECT * FROM democarpool_bookings WHERE id = $this->id");
}
public function nestPerson() {
$this->data->Person = new Person($this->data->Person);
$this->data->Person->load();
$this->data->Person->prepare();
}
public function nestCar() {
$this->data->Car = new Car($this->data->Car);
$this->data->Car->load();
$this->data->Car->prepare();
}
public function prepare() {
$this->data->_text = "";
$this->data->_html = $this->data->_text;
}
public function save() {
$this->stdSaveMain((object) array (
"table" => "democarpool_bookings"
));
}
public function delete() {
$this->db->performSQLString("DELETE FROM democarpool_bookings WHERE id = " . $this->id);
}
public function findByText($searchVal) {
;
}
}
<?php
require_once "../../../core/php/headers/dp.php";
if($action=="getForm") {
if(hasRole("user")) {
$myFormProcessor = new AX_FormProcessor();
$myFormProcessor->loadForm('../forms/Car.xml');
$myFormProcessor->renderAsXML();
}
else {
exitJSONError("Missing rights");
}
}
if($action=="getData") {
if(hasRole("user")) {
$myCar = new Car($data->id);
if($myCar->probeUTS($plUID,$plProps)) {
;
}
else {
$myCar->load();
$myCar->nestBookings();
$myCar->prepare();
$myCar->addLock();
}
$myCar->renderAsJSON();
}
else {
exitJSONError("Missing rights");
}
}
if($action=="saveData") {
if(hasRole("user")) {
$myCar = new Car($data->id);
$myCar->probeUTS($plUID,$plProps);
$myCar->overwriteWithData($data);
if($myCar->isValid()) {
$myCar->save();
$myCar->discardUTS();
}
$myCar->renderErrorStackAsJSON();
}
else {
exitJSONError("Missing rights");
}
}
if($action=="showLog") {
if(hasRole("user")) {
$myCompany = new Car($data->id);
$myCompany->renderLogAsJSON();
}
else {
exitJSONError("Missing rights");
}
}
<?php
require_once "../../../core/php/headers/dp.php";
if($action=="getForm") {
if(hasRole("user")) {
$myFormProcessor = new AX_FormProcessor();
$myFormProcessor->loadForm('../forms/Person.xml');
$myFormProcessor->renderAsXML();
}
else {
exitJSONError("Missing rights");
}
}
if($action=="getData") {
if(hasRole("user")) {
$myPerson = new Person($data->id);
if($myPerson->probeUTS($plUID,$plProps)) {
;
}
else {
$myPerson->load();
$myPerson->nestBookings();
$myPerson->prepare();
$myPerson->addLock();
}
$myPerson->renderAsJSON();
}
else {
exitJSONError("Missing rights");
}
}
if($action=="saveData") {
if(hasRole("user")) {
$myPerson = new Person($data->id);
$myPerson->probeUTS($plUID,$plProps);
$myPerson->overwriteWithData($data);
if($myPerson->isValid()) {
$myPerson->save();
$myPerson->discardUTS();
}
$myPerson->renderErrorStackAsJSON();
}
else {
exitJSONError("Missing rights");
}
}
if($action=="showLog") {
if(hasRole("user")) {
$myCompany = new Person($data->id);
$myCompany->renderLogAsJSON();
}
else {
exitJSONError("Missing rights");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE workInProgress>
<MultiForm id="Car" label="Car">
<Page id="Overview" label="Overview">
<Input id="_Cartype" label="Cartype" type="text" width="100%" disabled="true" />
<Input id="_Info" label="Info" type="textarea" width="100%" disabled="true" />
</Page>
<Page id="Basic data" label="Basic data">
<Input id="Cartype" label="Cartype" type="text" width="100%" />
<Input id="License" label="License" type="text" width="100%" />
</Page>
<Page id="Bookings" label="Bookings">
<Grid id="Bookings" label="Bookings" type="text" width="100%" >
<GridColumn id="Person" label="Person" type="single" />
<GridColumn id="FromDate" label="FromDate" type="date" />
<GridColumn id="FromTime" label="FromTime" type="time" />
<GridColumn id="ToDate" label="ToDate" type="date" />
<GridColumn id="ToTime" label="ToTime" type="time" />
<GridColumn id="Info" label="Info" type="text" />
<RowEditPage>
<Select id="Person" label="Person" type="single" sopts="Person" width="50%" />
<Input id="FromDate" label="From" type="date" width="30%" />
<Input id="FromTime" label="Time" type="time" width="20%" />
<br/>
<Spacer width="50%" />
<Input id="ToDate" label="To" type="date" width="30%" />
<Input id="ToTime" label="Time" type="time" width="20%" />
<br/>
<Input id="Info" label="Info" type="textarea" width="100%" />
<Spacer width="60%" />
<Button id="_ButtonAccept" width="20%" action="this.parentObj.acceptRowEdit()" eval="'Accept'" />
<Button id="_ButtonCancel" width="20%" action="this.parentObj.cancelRowEdit()" eval="'Cancel'" />
</RowEditPage>
</Grid>
</Page>
<Page id="Info" label="Info">
<Input id="Info" label="Info" type="textarea" height="100%" />
</Page>
</MultiForm>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE workInProgress>
<MultiForm id="Person" label="Person">
<Page id="Overview" label="Overview">
<Input id="_Name" label="Name" type="text" width="100%" disabled="true" />
<Input id="_LastBooking" label="Last Booking" type="textarea" width="100%" disabled="true" />
</Page>
<Page id="Basic data" label="Basic data">
<Input id="Name" label="Name" type="text" width="100%" />
<Input id="Address" label="Address" type="text" width="100%" />
<Input id="Telephone" label="Telephone" type="text" width="100%" />
</Page>
<Page id="Bookings" label="Bookings">
<Grid id="Bookings" label="Previous Bookings" type="text" width="100%" insert="false" edit="false" delete="false">
<GridColumn id="Car" label="Car" type="single" />
<GridColumn id="FromDate" label="FromDate" type="date" />
<GridColumn id="FromTime" label="FromTime" type="time" />
<GridColumn id="ToDate" label="ToDate" type="date" />
<GridColumn id="ToTime" label="ToTime" type="time" />
<GridColumn id="Info" label="Info" type="text" />
</Grid>
</Page>
<Page id="Info" label="Info">
<Input id="Info" label="Info" type="textarea" height="100%" />
</Page>
</MultiForm>
<?php
require_once "../../../core/php/headers/page.php";
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script>
$(document).ready(function () {
var myCurrentPL = myAx.myProcessLayerHandler.getProcessLayerById(<?php echo $plUID; ?>);
myCurrentPL.setStandardMultiFormButtons();
myCurrentPL.updateButtons();
myCurrentPL.myMultiForm = new AX_MultiForm({
ctx: myCurrentPL.ctx.find('#myMultiForm'),
dp: 'Car',
data: <?php echo json_encode($data); ?>
},myCurrentPL);
});
</script>
<title>Car: </title>
</head>
<body>
<div id="myMultiForm" class="MultiForm" style="height:100%;width:100%;background-color:#f8ffff;" />
</body>
</html>
<?php
require_once "../../../core/php/headers/page.php";
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script>
$(document).ready(function () {
var myCurrentPL = myAx.myProcessLayerHandler.getProcessLayerById(<?php echo $plUID; ?>);
myCurrentPL.setStandardMultiFormButtons();
myCurrentPL.updateButtons();
myCurrentPL.myMultiForm = new AX_MultiForm({
ctx: myCurrentPL.ctx.find('#myMultiForm'),
dp: 'Person',
data: <?php echo json_encode($data); ?>
},myCurrentPL);
});
</script>
<title>Person: </title>
</head>
<body>
<div id="myMultiForm" class="MultiForm" style="height:100%;width:100%;background-color:#f8ffff;" />
</body>
</html>
<?php
require_once "../../../core/php/headers/sopt.php";
if(hasRole("user")) {
$db = new AX_DB();
$sql = "SELECT id,
Name as _text,
Name as _html
FROM democarpool_persons";
$result = $db->fetchRowsBySQL($sql);
json_header();
echo '{"results": ' . json_encode($result) . ', "more": false }';
}
else {
exitJSONError("Missing rights");
}
|
AX Entities (explained)
- one project (module) folder
carsharing/
- one DataObject(s) folder
do/
holding as many DataObject(s) as you want.
- one DataProcessor folder
dp/
holding as many DataProcessors as you want.
- one axMultiForm folder
forms/
holding as many form definitions as you want.
- one Page folder
pages/
holding as many pages as you want.
- one
sopts/ folder holding the bits of code necessary to display select options for Cars and Persons.
|
Please note:
- you are free to diversify your project into as many modules as you want
- you are free to develop and deploy as many modules as you want
- you are free to serve an unlimited number of modules with one server installation
- there are many more special folder types, which we will get into more detail later