Agile Toolkit All In One Digest – Part 1

At this post we are going to provide an abstract of agile toolkit documents…

 

Installation:

Just extract the files!

 

Config:

Agile Toolkit uses an array for defining configuration.

$config['dsn']='mysql://user:secret@localhost/db';
$config['sample']['setting']=123;

 

The method

 api->getConfig('sample/setting',400);

is used to to retrieve config settings. The second argument to this function is a default value, and it’s used extensively throughout Agile Toolkit add-ons and components.

Copy the config-default.php and name it as config.php.

By default Agile Toolkit will read the config.php and config-defaults.php files. The settings in config.php will override the settings in config-defaults.php.

The file config-distrib.php is never loaded. It is a “template” that you can use to make your own copy of config.php.

Database Connection:

$config['dsn']='mysql://user:password@localhost/dbname';

// define port:
// $config['dsn']='mysql://user:password:8888@localhost/dbname';

// through socket
// $config['dsn']='mysql://user:password:/tmp/sock@localhost/dbname';

$config['dsn']=array('mysql','user','password', $options);

==

Just have these codes in mind for later!

$this->api->dbConnect();

/*If you wish to create additional connections, you can create 'DB' object directly like this:*/
$db = $this->add('DB')->connect($dsn);

====

$page->add('Form','my_form');

if($page->hasElement('my_form')){
  // has form
}

$page->getElement('my_form')->owner;  // refers back to $page

$model->add('MyObject',array('foo'=>'bar'));
echo $model->foo;

====

Working with existing objects

$this->hasElement($short_name) return child object if found, or false if not found.

$this->getElement($short_name) similar to hasElement() but will produce an exception if not found. Use this when chaining.

$this->destroy() remove the current object from its owner. For a view, this will remove it from rendered page.

$this->rename($new_short_name) can rename an object, but might not work with some objects.

$this->newInstance() will add a copy of the object and add into the same owner. Unlike cloning, object state is not copied.

Properties: $this->name name is unique to the system. $this->short_name is unique amongst owners children. $this->template reference to the SMlite template for the current view. $this->owner reference to the object whose add() was used (the parent). $this->api refers to the API class of the parent object.

=========

Chaining method calls:

$users = $this->api->db->dsql()
    ->table('user')
    ->where('age','>',30)
    ->order('name')
    ->get();

$dsql = $users = $this->api->db->dsql();
$dsql->table('user');
$dsql->where('age','>',30);
$dsql->order('name');
$users = $dsql->get();

=====

How can I know what the method will return?

Most of the methods in Agile Toolkit return an instance of the same object for chaining. There are exceptions, which are easy to spot:

// all objects have an add() method, returning an instance of a specified class
$form = $page->add('Form');

// Form has addField(), returning a Form_Field_<type>
$field = $form->addField('type','name');

// Models also have addField, but return a FieldDefinition
$field_definition = $model -> addField('surname');

// Grid's addColumn currently returns a Grid, but potentially can return other object
$do_not_chain = $gird->addColumn('type','name');

$dsql->order('name')
$users = $dsql->do_getAllHash();

js(), dsql()

$this->api->db->dsql() will return a new instance of a DBlite_dsql() object. All views have a js() method, which returns a new instance of a jQuery_Chain class.

$chain = $form->js(true);
$chain->hide();

=======

URL Components

PageManager is a controller used by ApiFrontend. It detects the URL of the browser and splits it into 3 components:

  1. base_url — http://example.com
  2. base_path — /atktest/
  3. page — user/settings

Properties are accessible through $api->pm->base_url, $api->pm->base_path and $api->page.

=========

Building URLs

 

$url=$page->api
    ->url('preferences/user');

$page->add('P')->set('URL is '.$url);
$page->add('P')->set('Absolute URL is '.
    $url->useAbsoluteURL());

/*

URL is /preferences/user

Absolute URL is http://agiletoolkit.org/preferences/user

*/

$url=$page->api
    ->url('search', array('q'=>'my book'));

$page->add('P')->set('URL is '.$url);
$page->add('P')->set('Absolute URL is '.
    $url->useAbsoluteURL());

/*

URL is /search?q=my+book

Absolute URL is http://agiletoolkit.org/search?q=my+book

*/

$page->api->stickyGET('user');

$url=$page->api
    ->url('search',
            array('q'=>'my book'));

$para=$page->add('P')->set('URL is '.$url.
        ' but same URL without user '.
        $url->set('user',false));

$page->api->stickyForget('user');

$page->add('Button')->setLabel('Refresh paragraph')
    ->js('click',
        $para->js()->reload(array('user'=>123)));

/*
URL is /search?user=123&q=my+book but same URL without user /search?q=my+book
*/

Relative Pages

Another handy feature in Agile Toolkit is the ability to generate URLs from relative paths.

Page Generated URL Notes
/ /index Using “/” generates URL to index page.
. /learn/understand/page/link Single dot refers to the current page. You can also pass “null” as 1st argument to url() to assume current page
.. /learn/understand/page Parent page in page hierarchy.
../object /learn/understand/page/object Adjacent page is specified as a sub-page of the parent page.
./test /learn/understand/page/link/test Finally you can link to a sub-page of a current page like this.

===

Adding Pages

Agile Toolkit has several ways to define new pages. Depending on the situation you should choose the most appropriate way.

Where a page is located depends on the API used. For example, for the command-line API (ApiCLI), the concept of pages is not defined at all. The table below shows the behaviour of ApiFrontend-based page routing.

Defined in Class used Template used Notes
API Method Page Default Probably the fastest way to create a page handler is to define a function inside the API class. The function must start with the prefix “page_”, and continue with the page name, with slashes replaced by underscores. Try to avoid using this method.
File page/mypage.php custom default or custom This is preferred way to define new pages, if you need dynamic content on them and optionally custom layout.
Template Only Page custom Ideal for custom pages. Simply create a single file with no PHP in it
Your own Custom Custom Implement your own pattern in the API class. You can use this method to fetch pages from the database, or to generate them dynamically
 function page_helloworld($page){
        $page->add('Button')->setLabel('Click Me');
    }

/*
Creating a separate class for each page:
*/
class page_helloworld extends Page {
    function init(){
        parent::init();
        $page=$this;

        $page->add('Button')->setLabel('Click Me');
    }
}

Static Pages

Static pages are the fastest way to get content into your web software. To build a high-performance application, you must make it simple and fast for it to retrieve content. The fastest way is to get content from a file.

Agile Toolkit allows you to create static pages simply by creating a file page/helloworld.html (inside the directory with your templates such as: templates/default)

<div id="<?$_name?>" class="g-10">
    <div class="g-6">
        <h2>Left Column</h2>
        <p>Hello</p> 
    </div>
    <div class="g-6">
        <h2>Right Column</h2>
        <p>World</p> 
    </div>
</div>

The definition of the id= property in the outermost element enables Agile Toolkit to interact with it through JavaScript. It is not a mandatory attribute, but is highly suggested to have.

This example also uses a built-in Grid System for 12 columns, and should output arranged into 2 columns. Similarly, you can use your own HTML code snippet.

you can call static page like this:

agiletoolkit-4.2.4/?page=how

===

Some examples:

<?php
class page_register extends Page {
    function init(){
        parent::init();

        $form = $this->add('Form');
        $form->addField('line','email');
        $form->addField('password','password');
        $form->addSubmit();
        $form->addButton('Cancel')->js('click')
            ->univ()->location($this->api->url('/'));

        if($form->isSubmitted()){
            $form->js()->univ()->alert('Thank you, '.$form->get('email').
                ', but this example is not ready yet')->execute();

        }
    }
    function defaultTemplate(){
        return array('page/register');
    }
}
<h1>Registration form</h1>
<div id="<?$_name?>" class="atk-row">
  <div class="span8">
    <?$Content?>
  </div><div class="span4">
    <div class="atk-notification ui-state-highlight ui-corner-all ">
        <div class="atk-notification-text">
            <i class="ui-icon ui-icon-info"></i>You must apply for new account before you can use this application.
        </div>
    </div>
</div>
</div>

====

Models:

 

$item = $this->add('Model_Item');

$res = $item->loaded(); // will contain false

$item->load($_GET['item_id']);

$res = $item->loaded(); // will contain true

//===================

$item = $this->add('Model_Item');

$item->tryLoadAny();

$item['price'] = 14.99;
$item['name'] = 'Mouse Pad';

$item->save();

/*

The above example will attempt to load ANY record into the model, update price and name then save back into database. If record couldn't be loaded, then a new record will be added. If record already exists in the database and field properties are exactly as specified, then save() will not perform database update.
*/

$item = $this->add('Model_Item');

$item->dsql()
  ->set('price',14.99)
  ->set('name','Mouse Pad')
  ->update();

====

Defining the Model

class Model_Item extends Model_Table {
  public $table='item';
  function init(){
    parent::init();

    $this->addfield('price');
    $this->addfield('name');
  }
}

//=================

class Model_Item extends Model_Table {
  public $table='item';
  function init(){
    parent::init();

    $this->addfield('price');
    $this->addfield('name');

    $cat = $this->leftJoin('category');
    $cat->addField('category_name','name');

    $this->hasMany('Order');
    $this->hasMany('Order_Completed');

    $this->addExpression('successful_orders')
      ->set($this->refSQL('Order_Completed')
      ->sum('amount'));
  }
}

 

=====

hasOne(), hasMany()

These methods allow you to establish relationship between different models (not tables).

 

====

DVD Rental Example

 

// lib/Model/Customer.php
class Model_Customer extends Model_Table {
  public $table='customer';

  function init(){
    parent::init();

    $this->addField('name');
  }
}

// lib/Model/DVD.php
class Model_DVD extends Model_Table {
  public $table='dvd';
  function init(){
    parent::init();

    $this->addField('code');

    $this->hasOne('Movie');
  }
}

// lib/Model/Movie.php
class Model_Movie extends Model_Table {
  public $table='movie';
  function init(){
    parent::init();

    $this->addField('name');
    $this->addField('year')->type('int');
    $this->addField('imdb')->caption('IMDB Link');
  }
}

// lib/Model/Rental.php
class Model_Rental extends Model_Table {
  public $table='rental';
  function init(){
    parent::init();

    $this->hasOne('Customer');
    $this->hasOne('DVD');

    $this->addField('date_rented')->defaultValue(date('Y-m-d'))->type('date');
    $this->addField('date_returned')->type('date');

    $this->addField('is_returned')->type('boolean')->defaultValue(false);
  }
  function returnMovie(){
    $this
      ->set('date_returned',date('Y-m-d'))
      ->set('is_returned',true)
      ->save();
  }
}

// page
$tabs = $page->add('Tabs');
$tabs->addTab('Customers')->add('CRUD')->setModel('Customer');
$tabs->addTab('Movies')->add('CRUD')->setModel('Movie');
$tabs->addTab('DVDs')->add('CRUD')->setModel('DVD');
$tabs->addTab('Rentals')->add('CRUD')->setModel('Rental');

 

===============

Part 2 of all in one series:
http://webelizer.net/228/agile-toolkit-all-in-one-digest-part-2.html

Leave a Reply

Your email address will not be published. Required fields are marked *