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
- 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.
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:
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');
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'); |
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
|
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 |
Code
$form=$page->add('Form'); |
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 |
Code
$url=$page->api->getDestinationURL('..')->set('foo','bar?'); |
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 |
Code
class MyDI extends Text { |
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 |
Code
$page->api->dbConnect(); |
May 11thcolumn->setButtonClass
setButtonClass allows you to add additional class to Grid button.
Result |
Code
$grid=$page->add('Grid'); |
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()){ |
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'); |
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', |
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 |
Code
$grid=$page->add('Grid'); |
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') |
April 11thremoved object->getName(), use object->name instead
Result |
Code
$page->add('Text') |
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 |
Code
$grid=$page->add('Grid',null,null,array('grid_striped')); |
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'); |
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 |
Code
$grid=$page->add('Grid'); |
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 |
Code
$grid=$page->add('Grid'); |
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();
