Intro ┬╗ Agile Toolkit - Introduction to UI

PHP programming language has earned it's popularity for it's simplicity, effectiveness and compatibility. Agile Toolkit follows same virtues and offers you two frameworks and wide range of add-ons that follow same design principles.

What is Agile Toolkit?

There are 3 core parts:

  1. Agile UI is a revolutionary Web Component Framework. It requires minimal PHP knowledge to build interractive and data-driven web apps. No knowledge of HTML/JS/SQL/CSS required to implement crucial parts of your web application.
  2. Agile Data is a next generation of Data Abstraction Frameworks. It makes work with database universal, foolproof and fast. Agile Data is not an ORM. It uses a different approach to minimize latency and performance loss when working with Cloud Databases.
  3. Add-ons are a very important part of Agile Toolkit. Everything is extensible - database drivers, field types, relation types, data structure, data aggregators, API servers, Actions, UI components, Form fields, Table columns, App types and UI layouts.

Agile Toolkit is suitable for building "Admin" interfaces, your internal ERP systems, web apps or API services. You can use Agile Toolkit in your vanilla PHP app or integrate into your legacy app. Agile Toolkit can complement popular full-stack frameworks in the UI and Data department.

A type of user who would find Agile Toolkit most beneficial is someone who is not familiar with Web App development yet and wishes to spend minimum time learning how to write web apps. We recommend that you have some general development experience. Agile Toolkit does not attempt to hide any of the underlying technologies, but rather make their knowledge necessary only in non-trivial scenarios.

1. Installs in seconds

Before you start:

Use composer to install Agile Toolkit:

composer require atk4/ui

Next, open file "test.php" in a text editor and type the following code snippet. Refresh your browser after saving the file.

require 'vendor/autoload.php';

// Initialize App and Layout first
$app = new \atk4\ui\App('My First App');
$app->initLayout('Centered');

// Your application starts here
$app->layout->add('HelloWorld');

You have just created a web application and even used your first "Component" in it (HelloWorld). Agile Toolkit comes with a lot of standard components and you can get even more by installing 3rd party add-ons.

2. Working with component using "Button" example

Components in Agile Toolkit implement various elements of User Interface - a button, a form, a menu or anything else. Try adding a "Button" to your app's layout.

$button = $app->layout->add(['Button', 'Hello there']);
  • 'Button' is a name of a standard UI component class.
  • 'Hello here' is button label.
  • $button will contain the Button object, so you can continue to interact with it.

The argument array passed to add() is something we call seed. It is a compact way to pass default properties and inject dependencies into components:

$button = $app->layout->add(['Button', 'Hello there', 'icon'=>'book', 'big red']);

The same logic can be also written like this:

use \atk4\ui\Button;

$button = new Button('Hello there');
$button->addClass('big red');
$button->icon = 'book';
$app->layout->add($button);

For each component we offer documentation, examples and demos. Here are some links for the Button component:

Component Purpose Docs Example Source
Button Displays clickable button, with optional icon, label or drop-down. Docs Demo, Usage Source

A Button, similarly to other components such as Header, Label or Message extends a View class. A lot of features are inherited. I'll try to cover some of the most important featuers here. (See demo: http://ui.agiletoolkit.org/demos/view.php)

3. Creating your own Components. Composition and Templates

Components can contain other components. In fact - "Layout" of your application is a component too! You can create complex interfaces by using one component inside another. (See demos: http://ui.agiletoolkit.org/demos/recursive.php and http://ui.agiletoolkit.org/demos/layouts.php).

Although all the components come with their own templates, you may override them. My next example creates a generic View object but injects a custom template object. We use a very simple template engine that contains no business logic and only marks the spots where text or other components can be inserted.

$plane = $layout->add(['View', 'template'=>new \atk4\ui\Template(
  '<div id="" class="ui statistic">
    <div class="value">
       
    </div>
    <div class="label">
      Flights
    </div>
  </div>'
)]);

$plane->template->set('num', rand(5, 20));
$plane->add(['Icon', 'plane'], 'Plane_spot');

If you intend to this template more than once, you should refactor it into a stand-alone component:

class Plane extends \atk4\ui\View
{
    public $defaultTemplate = './plane.html';

    protected $num = null; 

    protected $icon = null;

    function renderView() {
        if (!is_object($this->icon)) {
            $this->icon = new Icon($this->icon);
        }

        $this->add($this->icon, 'Plane_Spot');
        $this->template->set('num', isset($this->num) ? $this->num : rand(5, 20));        
        return parent::renderView();
    }
}

Also create plane.html file containing the template:

<div id="" class="ui statistic">
  <div class="value">
     
  </div>
  <div class="label">
    Flights
  </div>
</div>

You have just finished your first component! This is how you can use it:

// default icon and random number
$plane = $app->layout->add(new Plane());

// specify icon and number
$plane = $app->layout->add(new Plane(['icon'=>'book', 'num'=> 20]));

// you can also do this:
$plane = $app->layout->add(new Plane());
$plane->icon = 'book';
$plane->num = 20;

// you can also inject your own custom (or 3rd party) icon object
$plane->icon = new MyCustomIcon('abc');

4. Actions, Events and JavaScript integration

Server-side actions that are invoked from a PHP code are called "Actions". Typically they execute something inside a browser (using JavaScript). My next example will create Button and a block of Text (LoremIpsum). When button is clicked, the LoremIpsum text will be automatically reloaded.

$button = $app->layout->add(['Button', 'Refresh filler text below']);
$lorem = $app->layout->add('LoremIpsum');

$button->on('click', new \atk4\ui\jsReload($lorem));

In conventional web development implementing reloading is complex and can have several pitfals, but Agile Toolkit makes it simple. jsReload($view) object represents an action that will re-load contents of a specified $view. Action is a PHP object, that's very easy to manage and understand. Here are two other action examples:

  • $hide_action = $button->js()->hide(); - Action of hiding button.
  • $field_error_action = $form->error('field', 'Bad thing happened'); - Action of displaying error for a form field.

There are many ways to create actions that can be created by calling a method or creating object directly. You will find many interesting ways to create actions while learning Agile Toolkit. Always remember that Actions are not replacements for JavaScript but rather a way to bind it to your components in a convenient way.

5. Virtual Pages and Dialogs

Callback is an invisible class that is crucial to interractivity in Agile Toolkit. It allows you to generate a URL and specify a PHP callback. When URL is requested, callback is executed. The next example implements a 'View Source' button:

class ViewSourceButton extends \atk4\ui\Button
{
    public $content = 'View Source';  // default label

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

        $vp = $this->add('Callback');
        $vp->set(function() {
            highlight_file($_SERVER['SCRIPT_FILENAME']);
            exit;
        });
        $this->link($vp->getURL());
    }
}

You can now put ViewSourceButton anywhere and it will display the PHP file source when clicked.

The Callback is used as a base class for jsCallback which can be used to link browser events to a PHP code which will execute Action every time event is triggered.

My next snippet consits of two examples - first one will generate random number when page loads, then simply put in on a button when clicked. Clicking multiple times will not generate another random number. The second example will execute AJAX callback on every click generating random number every time and setting it as a button label:

$button = $app->layout->add(['Button', 'Generate random number ONCE']);
$button->on('click')->text(rand(1,20));

$button = $app->layout->add(['Button', 'Generate random number every time']);
$button->on('click', function($b) {
    return $b->text(rand(1,20));
});

Another class extends Callback is a VirtualPage. It allows you to load to create separate UI hierarchy which will not be normally visible, but could be specifically requested for example by a pop-up:

In the next example LoremIpsum will not be visible on the page, but should you click a button, it will send request back to PHP and load contents of VirtualPage inside:

$vp = $app->layout->add('VirtualPage');
$vp->add('LoremIpsum');

$app->layout->add(['Button', 'Show Dialog with LoremIpsum'])
  ->on('click', new \atk4\ui\jsModal('Dialog Title Here', $vp));

Agile Toolkit offers call-back features in such a way so that they can be contained within a more complex component and be further bulit upon.

6. Grid and Form

Equipped with some of the core functionality, Agile UI offers you a Form and Grid implementations which is way more advanced than any other Grid/Form implementation in PHP you can find.

Lets start with a basic Form. My next example will demonstrate how to create a form, add a field, define submission handler and invoke error/success response from a form handler:

$form = $app->layout->add('Form');

$form->addField('name');

$form->onClick(function($form){ 
    if (strlen($form->model['name']) < 3) {
        return $form->error('name', 'Please enter your name here');
    }

    return $form->success('Thank you, '.$form->model['name'].' we will be in touch!');
});

Your form will use dynamic AJAX request to submit the data and will automatically interpret response from the server. Form will actually understand any Action including the ones you or 3rd party may have implemented.

In most cases you will be using Form in conjunction with an actual Model. The heavy-lifting of the data is handled by Agile Data.

In my next example I'd like to create a simple TODO application. Define the following class, which will decribe a single ToDo item:

class ToDo extends \atk4\data\Model {
    public $table = 'todo_item';
    function init() {
        parent::init();

        $this->addField('name', ['caption'=>'Task Name', 'required'=>true]);
        $this->addField('due', [
          'type'=>'date', 
          'caption'=>'Due Date', 
          'default'=>new \DateTime('+1 week')
        ]);
    }
}

Next, we need to create object representing a storage. I'll use a session.

session_start();
$s = new \atk4\data\Persistence_Array($_SESSION);

Model must be associated with the peristence and specified to setModel() method of Form/Table:

$col = $app->layout->add(['Columns', 'divided']);
$col_reload = new \atk4\ui\jsReload($col);

$form = $col->addColumn()->add('Form');
$form->setModel(new ToDo($s));
$form->onSubmit(function($form) use($col_reload) {
    $form->model->save();

    return $col_reload;
});

$col->addColumn()->add('Table')->setModel(new ToDo($s));

This code will implement a pleasant application where you can easily enter your tasks and save them inside your PHP session:

7. Database Connectivity

How much work do you think it would take to store your TODO list inside a SQL table instead of session? Provided that you have a table already, you need to change exactly one line of PHP code:

$s = new \atk4\data\Persistence_SQL($dsn, $user, $pass);

If you DON'T have the SQL server, don't worry. Leave your example with the SESSION, because all of the code in this tutorial will work with either SESSION or SQL.

Like anything else - persistence classes can be supplied by 3rd party to connect your data model with new ways to store your data.

A more comprehensive database storage comes with perks. You get the ability to use features such as: SQL expressions, type mapping, JOINs, aggregation, sub-queries and many other features that the most advanced developers will find very alluring. For more information see:

8. Grid and CRUD

Once again, by combining the components created so far, we can now build even more powerful and interractive components. First - Grid wraps table by adding support for Menu, QuickSearch and Pagination.

You can see an example of a Grid here: http://ui.agiletoolkit.org/demos/grid.php

In fact - you can use Grid in your ToDo application allowing user to select multiple tasks to mark them as Completed. Replace the last line (the one adding table) with my next example, then see below for explanation:

$grid = $col->addColumn()->add(['Grid', 'paginator'=>false]);
$grid->setModel(new ToDo($s));

$grid->menu->addItem('Complete Selected', new \atk4\ui\jsReload($grid->table, [
    'delete'=>$grid->addSelection()->jsChecked()
]));

if (isset($_GET['delete'])) {
    foreach(explode(',', $_GET['delete']) as $id) {
        $grid->model->delete($id);
    }
}

Instead of Table the Grid offers some nice extras. I am disabling pagination and adding a new menu item, which will execute reload of Grid's table area and additionally pass list of selected elements through "delete" argument. If passed, it will find and delete those records.

CRUD class actually extends Grid. Go ahead and replace Grid class with a CRUD and see what happens. You should see additional Edit/Delete actions as well as new "Add" menu item. We certainly appreciate the "Edit" feature, but "Add" and "Delete" is something we already have implemented, so we need to disable these features. Replace this line:

$grid = $col->addColumn()->add(['Grid', 'paginator'=>false]);

with this:

$grid = $col->addColumn()->add(['CRUD', 'paginator'=>false, 'ops'=>[
  'c'=>false, 'd'=>false
]]);

You first Agile Toolkit application is now complete.

9. Deploy with Heroku

Why not deploy your application to the cloud and share with your friends? If you have never deployed PHP application below, you should try using free Heroku tier. Getting your app launched just takes a few steps described here: https://devcenter.heroku.com/articles/getting-started-with-php#introduction

If didn't write any code but simply scrolled through this tutorial, you can find a working TODO application here: http://money-lending.herokuapp.com/todo.php and the PHP source here: https://github.com/romaninsh/money_lending/blob/master/todo.php.

To repeat - The TODO application we created takes less than 50 lines and requires very basic technical knowledge..

10. Tell your friends!

Seriously, please do! Agile Toolkit is a brand new and we wish more developers would know about it. Help us by spreading the word or sharing a link to this tutorial.

What to do next?

Why not build some more apps? Here are some app ideas that you can build with Agile Toolkit as a practice:

App 2: Contact Form

Many sites feature a contact form. Your goal will be to create such a form, collect information and send it to yourself using a Sendgrid API and a template.

  • Focus on decorating your Contact Form, so fields are arranged nicely
  • Introduce and use 3rd party validation library
  • Implement your Contact Form as your own "Component"
  • Integrate your Contact Form into an existing framework or application.

Tweet your results with hashtag #atk4 and we will link best apps here.

App 3: Money Lending App

https://github.com/atk4/money-lending-tutorial

Let's create a more comprehensive application. We need an application where anyone can register then login with their "email" and "password". Once inside, they should be able to create their own list of "Contacts", then be able to "Lend" money to a contact.

Make it possible so you can lend more than once to the same contact. Also - make app generate unique URL that you can send direrctly to your contact and which they can click to see how much they owe you and how much they must repay right now.

Think about various real-life situations and implement them - partial repayment, multiple loans for the same friend and time limits on different loans. This example focuses on:

  • Creating multi-user and multi-page applications
  • Registration, login, logout and related functionanlity
  • Defining permissions and designating Administrator accounts
  • Building

Tweet your results with hashtag #atk4 and we will link best apps here.

App 4: Online auction

It's time to sell your old gadgets. Do you have a phone that you no longer use? Let's create an auction for it!

You have to write an app where you can enter details of your item (name, description, starting price, expiration date), then share the URL with your friends who can bid on it.

Your friends need to create an account and log-in before they can bid, so that you know who they are. Personalize your app with your unique ideas. Implement the "minimum bid" policy, e.g. If current bid is "5" and someone enters bid "10" it increases only to 6. If there is another user who bids 8, then your system automatically increases bid of the first user to "9".

Show how much time is left on a bid.

App 5: Advertisement Board

Create a site with a number of categories (household, garden, car, etc) and actions (buy, sell, rent, exchange). Allow users to fill out a form with the posting details. Displayed advertisement in the appropriate category. Extend your app to include "admin's verification" - we don't want bad ads to be advertised. Add an ability to display ads only for some time period (e.g. 30 days).

Integrate payment gateway, so that users may pay to "feature their ad". This will extend their ad's lifetime to 60 days, give it a "HOT" badge and place it on top of the list in a category.

Compare your project with a professional classifieds sites, see which features you are lacking and implement some of them into your own project.

App 6: Twitter clone

Time to post tweets on your timeline.

Implement your own twitter. Allow other users to follow you. Find and implement the most essential features inside your application.