What is coming up or was just introduced in Stable and Development version of Agile Toolkit/?> download, development version, stable version, changes, updates, changelog, recent changes/?>
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 GuideVersion 4.1.4 is a maintenance release.
Version 4.1.3 has incorporated a number of bugfixes and improvements since the last release such as:
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().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'); /?>
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'); /?>
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.
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.
$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.
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
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.
$form=$page->add('Form_Plain'); $form->setAttr('method','post'); $form->addInput('text','name','John'); $form->addInput('text','surname','Blogs'); $form->addInput('submit','submit','Send'); /?>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.
Traditionally calling $api->auth->logout() would destroy login info, issue redirect to index and never return. Now, passing "false" can avoid redirect: logout(false);
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.
$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(); } /?>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
$form=$page->add('Form'); $form->addField('password','password') ->add('Text',null,'after_field') ->set('Use Spaces!'); $form->setFormClass('vertical'); $form->addSubmit(); if($form->isSubmitted()){ $form->js()->univ()->alert('Length is '. strlen($form->get('password'))) ->execute(); } /?>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
$url=$page->api->getDestinationURL('..')->set('foo','bar?'); $page->add('Text')->set($url); /?>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;
class MyDI extends Text { function init(){ parent::init(); $this->set($this->di_config['text']); } } $page->add('MyDI',array('text'=>'test123')); /?>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); } /?>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
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
Adding some consistency by always moving column with delete button to be the last in grid.
$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); /?>setButtonClass allows you to add additional class to Grid button.
$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'), )); /?>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
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
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.
Similarly how you can check form conditions, you can now do the same with buttons.
if($page->add('Button')->isClicked()){ $this->js()->univ()->alert('Random is: '.rand(1,100))->execute(); } /?>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.
$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'); }); /?>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.
$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(); } /?>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'); /?>Properly aligns not only the money, but also the title
$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'), )); /?>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(); /?>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); /?>
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.
$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'), )); /?>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.
$form=$page->add('Form'); $form->addField('autocomplete','test') ->setValueList( array('John','Peter','Jane')); /?>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'); /?>To change format, add $config['locale']['timestamp']='Y-m-d'; or $config['locale']['datetime'].
$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')), )); /?>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.
You can use <?_link?> or any other field tag as a template for "link" column, in setTemplate().
$grid=$page->add('Grid'); $grid->addColumn('text','name'); $grid->addColumn('link','details'); $grid->addColumn('link','proflie') ->setTemplate('xx'); $grid->setStaticSource(array( array('id'=>1,'name'=>'John', 'details'=>'John Details'), array('id'=>2,'name'=>'Peter', 'details'=>'Peter Details'), )); /?>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 /?>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(); /?>