Version 4.2

Version 4.2 is a major update of Agile Toolkit focused on impoving compatibility, implementing new Model architecture and user interface.

Version 4.2 Migration Guide

Version 4.1

What's new in 4.1.4?

Version 4.1.4 is a maintenance release.

  • Enhancement: ApiWeb can now be used much more flexible
  • Enhancement: Field_upload: Change template through property $format_files_template
  • Enhancement: It's possible now to reset form's "changed" status on form submit
  • Tweak: Class files are included from add()
  • Tweak: Attempting to use non-existant spot produces error during init() not during render()
  • Tweak: Removed upgrade checker from ApiWeb and moved it into ApiFrontend
  • Tweak: TMail's default mailer no longer adds duplicate To: or Subject: lines
  • What's new in 4.1.3?

    Version 4.1.3 has incorporated a number of bugfixes and improvements since the last release such as:

    • Added basic caching into Template Engine for about 30% speed improvement
    • setModel() on forms no longer adds "Save" button by default.
    • Rewrite of "TMail" class. New one being much more powerful.
    • Compat controller updated if your software is affected by the changes.

    Compatible Upgrade

    If you are upgrading from 4.1.2 and are concerned about compatibility, you should add this to your API initialization:

      $this->add('Controller_Compat');
    adds a whole 4 new examples into the downloadable ZIP archive. To keep things simple we decided to drop all the different ZIP files and have only one - agiletoolkit-4.1.2.zip. There are also bugfixes such as ability to use full url with getDestinationURL().

    August 16thEnable use of callback in $field->validateField()

    $form $page->add('Form');
    $field $form->addField('line','age');
    $field->validateField(function($field){
        if(
    $field->get()<18)return 'Must be 18+';
    });
    $form->addSubmit();

    August 16th$api->jui->addStaticInclude()

    Calling jui->addInclude() or js()->_load() will attempt to load JavaScript file dynamically through AJAX. Some 3rd party JavaScript add-ons do not like that. Previously developer would had to manually add include text into shared template, now you can simply call:

    $this->api->jui->addStaticInclude('myjsfile');

    What's new in 4.1 (since 4.0)

    August 16thAdd getColumn() to DBlite

    $array_of_values $this->api->db->getColumn($query);


    $array_of_values $dq->do_getColumn();

    August 16th$api->jui->addStaticInclude()

    Calling jui->addInclude() or js()->_load() will attempt to load JavaScript file dynamically through AJAX. Some 3rd party JavaScript add-ons do not like that. Previously developer would had to manually add include text into shared template, now you can simply call:

    $this->api->jui->addStaticInclude('myjsfile');

    July 10thPDO DB under construction

    It's not in the works. lib/DB.php and also lib/DB/dsql.php contain half-finished implementation of PDO layer. If you need to implement it yourself and you can't wait, you can use this class to make your own. We expect PDO to arrive sometime in 4.1.1 or bit more later.

    July 6thDynamic Methods

    Agile Toolkit now supports dynamic methods. Avoid using them at any costs, since they are slower than regular methods and are quite confusing for developers. Dynamic method allows to register method for one or all objects

    $this->api->addGlobalMethod('helloworld',array($this,'helloworld'));

    This code will allow calling $anyobject->helloworld();. This is quite effective way to maintain backwards compatibility when methods are being cleaned up. There is also a function for registering method for single function. It is useful if controller wants to register function inside API namespace. Possibly PathFinder could have registered locate() and locateURL() functions through this approach, to keep API clean, however since it's very essential controller, it's been done in old-fashioned way for simplicity and speed.

    July 6th$this->frame() is no more

    $view->frame() used to be a handy method to add a frame with a header. This method is now obsolete in favour of the new form:

    // $frame=$view->frame('My Frame Title');

    $frame=$view->add('Frame')->setTitle('My Frame Title');

    If you have been relying on this function, there is actually a compatibility controller. If you add it, then old format would still work.

    $this->api->add('Controller_Compat');
    $frame=$view->frame('My Frame Title');

    This controller also adds removed support for ajax() function for all views.

    July 6thAdded Unit Test suite

    Unit tests basics is quite simple. Execute a function and compare results with expected. Agile Toolkit provides a simple implementation for Unit tests, however with few nifty features

    class page_mytest extends Page_Tester {
        function 
    prepare(){
            return 
    $this->add('View');
        }
        function 
    test_name($t){
            return 
    $t->name;
        }
        function 
    test_shortname($t){
            return 
    $t->short_name;
        }
    }

    Firstly, there are no value to compare with. Testing framework aims at remembering correct value on it's own and comparing with new value. Secondly, each test is a function, which makes it possible for a testing script to execute each test multiple times. Additionally, function prepare() is called before each test, which is designed to prepare data to be used within test. This way you can always start test with a clean object to play with.

    This testing framework will be further enhanced. We plan to add stress-test and storing results in mysql as well as automated re-testing of multiple pages like this without verbose output.

    Another feature supported is "variations". It allows you to use different prepare functions for tests. For example if you implementing new version of your controller and you want to test it against old one - it will show you output side-by-side.

    There is also a new project called atk4-tester, which is growing collection of tests for testing framework

    June 28thAdded implementation of plain forms

    Agile Toolkit forms are full featured. What if you want to make a plain form? Such as the one to send output to PayPal. Now there is implementation you can use and it's insanely simple and powerful.

    If you want to use custom template, pass a 4th argument to add('Form_Plain') and use 4th argument for addInput to specify tag, where input should appear.

    Result

     

    Code

    $form=$page->add('Form_Plain');
    $form->setAttr('method','post');
    $form->addInput('text','name','John');
    $form->addInput('text','surname','Blogs');
    $form->addInput('submit','submit','Send');

    June 26thStored procedure import extension is now *.sql

    Do you know that you can create doc/storedfx/ directory and put source of your stored procedures in there? After each run it will always execute storedfx/*.sql files. It used to be files ending with *.manual, but *.sql makes so much more sense.

    June 16thAdded support for logout without redirect

    Traditionally calling $api->auth->logout() would destroy login info, issue redirect to index and never return. Now, passing "false" can avoid redirect: logout(false);

    June 15thAdded implementation of sha256/salt encryption

    Auth classes allow you to call ->usePasswordEncryption(). This change the way how encryptPassword() function works and also how login is validated. Now you can use "sha256/salt" encryption, and also encryptPassword takes second argument, which is a salt.

    Result

     

    Code


    $encryptions
    =array('md5','sha1','rot13','sha256/salt');

    $form=$page->add('Form');
    $form->setFormClass('vertical');
    $form->addField('password','password');
    $form->addField('line','salt');
    $form->addField('dropdown','enc')
      ->
    setValueList($encryptions);
    $form->addField('text','result')
      ->
    setProperty('style','width: 250px');
    $form->addSubmit();
    if(
    $form->isSubmitted()){
        
    $auth=$this->add('BasicAuth');
        
    $auth->usePasswordEncryption($encryptions[$form->get('enc')]);
        
    $form->getElement('result')->js()->val(
            
    $auth->encryptPassword($form->get('password'),
              
    $form->get('salt'))
            )->
    execute();
    }

    June 15thTrim password field and enable normalize() in general for fields

    If you are building custom field, you can now use normalize() function.

    function normalize(){
        
    $this->set(trim($this->get()));
        
    parent::normalize();
    }

    Additionally password field will automatically normalize itself by trimming

    Result

    Use Spaces!
     

    Code

    $form=$page->add('Form');
    $form->addField('password','password')
      ->
    add('Text',null,'after_field')
      ->
    set('<ins>Use Spaces!</ins>');
    $form->setFormClass('vertical');
    $form->addSubmit();
    if(
    $form->isSubmitted()){
        
    $form->js()->univ()->alert('Length is '.
            
    strlen($form->get('password')))
          ->
    execute();
    }

    May 24thURL->set() implemented

    When you execute $api->getDestinationURL() it returns an object. This object converts itself into URL in string context. You can execute few methods, to interact with that URL such as useAbsoluteURL(). Now you can also use set() to add more parameters

    Result

    /index?foo=bar%3F
     

    Code

    $url=$page->api->getDestinationURL('..')->set('foo','bar?');
    $page->add('Text')->set($url);

    May 26thImplemented argument passing to init()

    Normally all the dependencies object is receiving through $this->api. It's generally a bad practice in Agile Toolkit to take any input inside init() method. Instead chaining should be used and logic should be stored in render(). However if you think that you still need to pass something into init() method, now there is a way.

    Pass array as a second argument to add() function and it will be available through $this->di_config;

    Result

    test123
     

    Code

    class MyDI extends Text {
        function 
    init(){
            
    parent::init();
            
    $this->set($this->di_config['text']);
        }
    }

    $page->add('MyDI',array('text'=>'test123'));

    May 24thAdded ButtonSet

    $bs=$page->add('ButtonSet');
    $bs->add('Button')->set('<b>B</b>');
    $bs->add('Button')->set('<i>I</i>');
    $bs->add('Button')->set('<u>U</u>');

    May 20thAdd ability to setup default pathfinder locations

    Pathfinder class needs to be loaded very early in your application. By the time init() is executed, it's already been initialized and ready to load your classes. How do push some paths before default ones are in effect? Now you can re-define $api->addDefaultLocations($pathfinder);

    In following example, directory "myplugin" located in the base directory of your application can contain "includes", "javascript" and "tpl" folders. Resources in those folders will take precedence over any other location

    function addDefaultLocations($pathfinder,$base_dir){
        
    $pathfinder->addLocation('myplugin',array(
            
    'php'=>'includes',
            
    'js'=>'javascript',
            
    'template'=>'tpl',
          ))
          ->
    setBasePath($base_dir);
    }

    May 18thFix UI-test

    Did you know that there is a page called "uitest" which is comes enabled by default? You can see different elements on it. Good for testing your theme. Try it, http://localhost/atk4-example/?page=uitest

    May 18thUse 10-columns instead of 12 by default

    Give class="g-row" to your div and then inside that you can use classes like "g-4", "g-8" to slice the space horizontally. The total amount of values should be exactly 10. You can also use "g-max" for full-width column

    May 11thDelete button is always last in grid

    Adding some consistency by always moving column with delete button to be the last in grid.

    Result

    Name Surname Delete
    Jeremy Jeremy
     

    Code

    $page->api->dbConnect();
    $grid=$page->add('Grid');
    $grid->addColumn('delete','delete');
    $grid->addColumn('text','name');
    $grid->addColumn('text','surname');
    $grid->setSource('user');
    $grid->dq->limit(5);

    May 11thcolumn->setButtonClass

    setButtonClass allows you to add additional class to Grid button.

    Result

    Name Salary B1 B2
    John 2,000.00
    Peter 4,200.00
    Minus -200.00
     

    Code

    $grid=$page->add('Grid');
    $grid->addColumn('text','name');
    $grid->addColumn('money','salary');
    $grid->addColumn('button','b1');
    $grid->addColumn('button','b2')->setButtonClass('red ');
    $grid->setStaticSource(array(
                array(
    'name'=>'John','salary'=>'2000'),
                array(
    'name'=>'Peter','salary'=>'4200'),
                array(
    'name'=>'Minus','salary'=>'-200'),
                ));

    May 8thadd getModel() to all views

    You can now call setModel() and getModel() on any view. If you specify name of the model (string) to setModel() it will be instantiated and getModel() would always return object

    May 8thGrid->getColumn

    As you know, according to convention, add* methods return instance of a new column. Grid, however, does not add any objects when you use addColumn. It however remembers which column was last added and makes possible for such constructions:

    $grid->addColumn('text','name')->makeSortable();

    What if you didn't manage to make column sortable right away? Now there is getColumn function to help:

    $grid->addColumn('text','name');
    $grid->addColumn('text','surname');

    $grid->getColumn('name')->makeSortable();

    This is particularly helpful if you are using setModel() to initialize columns

    May 5thDefault excetpion for form = validity check

    Any object in Agile Toolkit has a exception() function. This function takes the string and returns new exception which you can throw. The primary reason for the function is syntactic sugar - you can chain calls on a function, while you can't chain if you use "new". Chaining of exceptions is used for adding more information. Remember that parameter for the exception() will be localized, and possibly displayed to user, while additional data can be passed for debugging.

    Different objects can use different exceptions classes. Now function thrown Exception_ValidityCheck exception by default.

    throw $form->exception('Message For User')
      ->
    setField('fieldname')
      ->
    addMoreInfo('foo',$bar);

    There is another type of exception, called Exception_ForUser. Executing $page->exception() will trigger that instead.

    May 2thadded button->isClicked() handler

    Similarly how you can check form conditions, you can now do the same with buttons.

    Result

     

    Code

    if($page->add('Button')->isClicked()){
        
    $this->js()->univ()->alert('Random is: '.rand(1,100))->execute();
    }


    May 2thadded form->onSubmit()

    Historically form would have a method onSubmit() which would return "true" when page was pulled from the form's "submit" AJAX request. With the release of PHP 5.3 closures are now available. onSubmit() method accepts one argument, a callable, which is executed right away if form is submitted. The benefit of this approach is that form will automatically capture validation errors and display them. You can also return JS from that function which would be executed automatically.

    Result

     

    Code

    $form=$page->add('Form');
    $form->setFormClass('vertical');
    $form->addField('line','age');
    $form->addSubmit();
    $form->onSubmit(function($form){
        if(
    $form->get('age')<5)
          throw 
    $form->exception('Too young')
            ->
    setField('age');

        return 
    $form->js()->univ()->successMessage('thank you');
    });

    May 2thadded PathFinder's methods: search() and searchDir()

    Pathfinder is here to search for resources. $api->locate() is one function you migth already know. $api->pathfinder->search() and searchDir() allows you to receive list of files in directories across multiple paths. Great for implementing dynamic plug-ins in your application.

    Result

     

    Code

    $models=$this->api->pathfinder->searchDir('template',
        
    'css');

    $form=$page->add('Form');
    $form->setFormClass('vertical');
    $form->addField('dropdown','models')
        ->
    setValueList($models);
    $form->addfield('line','path');
    $form->addfield('line','url');
    $form->addSubmit('Resolve');

    if(
    $form->isSubmitted()){
        
    $js=array(); $i=$form->get('models');
        
    $js[]=$form->getElement('path')->js()->val($this->api->locate('template','css/'.$models[$i]));
        
    $js[]=$form->getElement('url')->js()->val($this->api->locateURL('template','css/'.$models[$i]));
        
    $form->js(null,$js)->execute();
    }

    April 4thform_body Tag Renamed

    Default Form template used to contain <?form_body?> tag. That's the place in the form.html template, where fields are located. It's now been renamed into standard <?Content?> tag making addition of other elements into form body much easier:

    $f->add('H2')->set('appears after last field');

    April 4thAlign "money" column type in the grid to the right

    Properly aligns not only the money, but also the title

    Result

    Name Salary
    John 2,000.00
    Peter 4,200.00
    Minus -200.00
     

    Code

    $grid=$page->add('Grid');
    $grid->addColumn('text','name');
    $grid->addColumn('money','salary');
    $grid->setStaticSource(array(
                array(
    'name'=>'John','salary'=>'2000'),
                array(
    'name'=>'Peter','salary'=>'4200'),
                array(
    'name'=>'Minus','salary'=>'-200'),
                ));

    April 7thDSQL debug output is better

    Setting debug mode on DSQL object will output breakdown of parameters

    $str=$page->api->db->dsql()->debug()
        ->
    table('foo')
        ->
    field('bar')
        ->
    where('x>',123)
        ->
    limit(10)
        ->
    select();

    April 9thGrowl (ui.atk_notify.js) shows messages better

    Result

     

    Code

    $page->add('Button')->js('click')
        ->
    univ()
        ->
    successMessage
            
    ('Yey, it works!');

    April 11thremoved object->getName(), use object->name instead

    Result

    AgileWeb_whatsnew_doc_example_13_view
     

    Code

    $page->add('Text')
      ->
    set($page->name);

    April 11thNew way for handling exceptions

    Introducing new way of producing exception in Agile Toolkit. Calling exception() method will return object of the right exception class. For example calling $db->exception() will properly return database-related exceptino and might also include some object-related information, while exception generated in model, would generate validity exception.

    Be sure to not include any variables into 1st argument to exception, this string will be localized. Instead specify relevant arguments by calling addMoreInfo()

    throw $this->exception('Something went wrong')
        ->
    addMoreInfo('niceinfo',$info);

    April 13thAdd zebra template for grid

    use 4nd argument of array('grid_stripped') to use this new template. Remember that you can always add your own templates to further ehance look of your objects.

    Result

    Name Salary
    John 2,000.00
    Peter 4,200.00
    Minus -200.00
     

    Code

    $grid=$page->add('Grid',null,null,array('grid_striped'));
    $grid->addColumn('text','name');
    $grid->addColumn('money','salary');
    $grid->setStaticSource(array(
                array(
    'name'=>'John','salary'=>'2000'),
                array(
    'name'=>'Peter','salary'=>'4200'),
                array(
    'name'=>'Minus','salary'=>'-200'),
                ));

    April 15thImplement Auto-complete

    use 4nd argument of array('grid_stripped') to use this new template. Remember that you can always add your own templates to further ehance look of your objects.

    Result

     

    Code

    $form=$page->add('Form');
    $form->addField('autocomplete','test')
        ->
    setValueList(
                array(
    'John','Peter','Jane'));

    April 15thadd ability to disable full-screen mode (for true gs960)

    By default your Agile Toolkit application uses full width of the screen. If you want to have true 960gs, then you should add the following to your Api's init() method.

    $this->template->del('fullscreen');

    April 19thShowing timestamps

    To change format, add $config['locale']['timestamp']='Y-m-d'; or $config['locale']['datetime'].

    Result

    Ts Dt
    01/11/2014 00:00:00 01/11/2014 00:00:00
     

    Code

    $grid=$page->add('Grid');
    $grid->addColumn('timestamp','ts');
    $grid->addColumn('datetime','dt');
    $grid->setStaticSource(array(
                array(
    'ts'=>date('Y/m/d'),'dt'=>date('Y/m/d')),
                ));

    April 25thAllow to substitute "Grid" class

    Many components rely on Grid component. Often a developer would want to make system-wide changes to the Grid component. Push mechanism allows for all the components to use the new version. Push is implementing by redefining "Grid" class. By default it's defined like this:

    class Grid extends Grid_Basic{}

    All of the documentation, addons and user code must use "Grid" and not "Grid_Basic". This allows you to define this class locally inside your lib/Grid.php and redefine some of the methods there.

    April 26thImprove "link" format in Grid

    You can use <?_link?> or any other field tag as a template for "link" column, in setTemplate().

    Result

    Name Details Proflie
    John John Details xx
    Peter Peter Details xx
     

    Code

    $grid=$page->add('Grid');
    $grid->addColumn('text','name');
    $grid->addColumn('link','details');
    $grid->addColumn('link','proflie')
        ->
    setTemplate('<a href="..">xx</a>');
    $grid->setStaticSource(array(
                array(
    'id'=>1,'name'=>'John',
                    
    'details'=>'John Details'),
                array(
    'id'=>2,'name'=>'Peter',
                    
    'details'=>'Peter Details'),
                ));

    April 27thOur standard menu is joined by Menu_Light

    This menu operates entirely on templates.

    // Regular
    $menu=$page->add('Menu');
    $menu->addMenuItem('hello');
    $menu->addMenuItem('world');

    // Lightweight
    $menu=$page->add('Menu_Light',null,null,array('mymenu'));
    // items are defined in mymenu.html

    April 28thRemoved "jui" theme, added "default" and "elephant"

    Look into your index.php file. It might still be using "jui" theme. We suggest to remove argument alltogether or set to "elephant" for the older look of Agile Toolkit.

    $api=new Frontend('myapp');
    $api->main();

    April 29thLogin form looks much cooler

Development History

All changes to the development version of Agile Toolkit are listed below.

Agile Toolkit Core
  • Release 4.2 NEW!
  • Release 4.1.2
  • August 2011
  • July 2011
  • June 2011
  • May 2011
  • April 2011
  • Mart 2011
  • February 2011

    • To stay up to date, by following @atk4 on twitter. Use Git / master branch for most recent version.