Version 19, last updated by Stian Didriksen at 25 Feb 00:34 UTC
3-database
How to update your trunk code to work with the 3-database merge
Getting the Query Object
$query = new KDatabaseQuery();
---->
$table = KFactory::get($this->getTable());
$query = $table->getDatabase()->getQuery();
Getting the Database Object
$this->_db
---->
$database = KFactory::get($this->getTable())->getDatabase();
Every reference must be updated, for example
$results = $this->_db->fetchObjectList($query);
---->
$database = KFactory::get($this->getTable())->getDatabase();
$results = $database->fetchObjectList($query);
$id = $this->_db->fetchResult($query);
---->
$database = KFactory::get($this->getTable())->getDatabase();
$id = $database->fetchResult($query);
$this->_db->execute($query);
---->
$database = KFactory::get($this->getTable())->getDatabase();
$database->execute($query);
Be sure to call the parent in buildQueryWhere()
If you call _buildQueryWhere() in a model, be sure tocall the parent, otherwise when updating a table row, all the rows inthat table will be affected.
protected function _buildQueryWhere(KDatabaseQuery $query)
{
parent::_buildQueryWhere($query);
....
....
Complete list of changes per package
1. KDatabase
Added support for ENUM and SET datatypes in KDatabaseAdapterMysqli. For both KDatabaseSchemaField::size will return an array containing the enumerated values.
-
Added support for unbuffered queries. For increased performance all KDatabaseAdapter::fetchX functions perform unbuffered queries instead of storing the result on the mysql server.
You can perform an unbuffered query manually by setting the $mode argument of KDatabaseAdapter::select and/or execute to KDatabase::RESULT_USE, default is KDatabase::RESULT_STORE.
-
Changed all instances of 'field' to 'column' as discussed here : http://groups.google.com/group/nooku-framework/browse_frm/thread/bdbc... This change has a large effect on the API. A number of functions have been changed most notably any function that has the word 'Field' or 'Fields' in it has changed to 'Column' or 'Columns'.
The biggest change for simple extensions will be KModelTable::buildQueryFields, which has been changed to KModelTable::buildQueryColumns. In most cases changing this will be enough to get your extension up and running again.
Renamed KDatabaseAbstract::fetchAssoc to fetchArray, fetcAssocList to fetchArrayList, fetchResult to fetchField and fetchResutList to fetchFieldList.
To improve the flexibility and robustness of the database layer KDatabaseTable::insert, update and delete function now only accept a KDatabaseRowAbstract object. Support for raw data arrays has been removed. In a next step I will also add support for rowsets.
1.1. KDatabaseTable
-
Added a KDatabaseAdapter::getIndetityKey to return the auto_increment field and changed the getPrimaryKey function to getPrimaryKeys which now returns an array of primary keys.
This change is a next step in improving support for tables that don't have a auto_increment field and also tables that defines composite primary keys.
For a deeper insight in the reason behind this changes http://weblogs.sqlteam.com/jeffs/archive/2007/08/23/composite_primary...
Added $mode parameter to KDatabaseTableAbstract::select(). Possible modes are KDatabase::FETCH_ROW and KDatabase::FETCH_ROWSET. Default is KDatabase::FETCH_ROWSET. Also improved select function to return an empty row or rowset object if no query information was passed.
Renamed the KDatabaseTableAbstract:::$_identity_key property to identity_column and refactored identity_column support. The identity_column is now set during object construction. The getIdentityColumn function will return the mapped column name.
-
Removed of KDatabaseTable::fetchRow and KDatabaseTable::fetchRowset in favor of KDatabaseTable::select. Also added a KDatabaseTable::getRow and getRowset function, both will return a identifier for the rowset or row that belongs to the table. For more about this also see : http://groups.google.com/group/nooku-framework/msg/ea546cf626199f18
The new select function will allays return a KDatabaseRowset. To select the firs row (the equivalent of the old fetchRow) function you can do :
$row = $table->select($query)->current();The select method now also implements the command chain which will allow for a lot of flexibility in the upcoming database behaviors.
Removed getType, getMaxOrder and order functions. Removed $_info variable, metadata is now cached in the database adapter. KDatabaseTableAbstract constructor now auto-enqueue's all available table behaviors in the the table's command chain.
1.1.1 Filters
-
You can now override the default behavior and specify which filter a field needs to use. This is especially handy for example to filter rich-text fields as html. This was a question posted by Ronald Pijpers some time ago : http://groups.google.com/group/nooku-framework/browse_thread/thread/d...
You can add filters in 2 ways :
Through the API, example :
class ComProfilesTableDepartments extends KDatabaseTableAbstract { public function __construct(array $options = array()) { $options['name'] = 'profiles_view_departments'; $options['base'] = 'profiles_departments'; $options['filters'] = array( 'alias' => 'alias', 'description' => 'html' ); parent::__construct($options); } public function filter($data) { settype($data, 'array'); //force to array if(empty($data['alias'])) { $data['alias'] = $data['title']; } return parent::filter($data); } }Through table column annotations, example
To set a filter annotation use
COMMENT '@Filter("filter")'. For example for harbour this would give the following table schema definition :CREATE TABLE IF NOT EXISTS `#__harbour_boats` ( `harbour_boat_id` SERIAL, `name` varchar(255) NOT NULL, `enabled` tinyint(1) NOT NULL default '1', `description` text NULL COMMENT '@Filter("html, tidy")', `created_on` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, `created_by` int(11) NOT NULL default 0, `modified_on` datetime NOT NULL default '0000-00-00 00:00:00', `modified_by` int(11) NOT NULL default 0, `locked_on` datetime NOT NULL default '0000-00-00 00:00:00', `locked_by` int(11) NOT NULL default 0 ) ENGINE=MyISAM DEFAULT CHARSET=utf8Notice the
COMMENT '@Filter("html, tidy")', for the description field. Using annotations you don't need to create specialised table classes to define table filters and behaviors.
1.1.2 Views
Added a KDatabaseTableAbstract::getInfo() function which will return the table schema information. Based on this information the table can determine it's own type, either 'BASE' for a regular table or 'VIEW' for a table view.
Added KDatabaseTableAbstract::getType() function which will return the table type : 'BASE' or 'VIEW'.
Changed KDatabaseTableAbstract::getTableName() function to getName(). This function will return the actual table name used in the database schema without the table prefix.
Added a KDatabaseTableAbstract::getBase() function which will return the name of the base table in case the table is of type 'VIEW'. If the table is a base table getBase() will return the same as getName().
-
All CRUD related functions in KDatabaseTableAbstract now use getBase() instead of getName to retrieve the database table name. This means that CRUD operations are now executed on the base table and never on the view itself.
Note : This new implementation of how views work follows how MySQL and most other database drivers deal with them internaly. Only instead of letting the driver figure out if a view is updatebale (which is mostly not the case) or not we are doing it in our table class itself. For more information about MySQL views you can go here : http://dev.mysql.com/doc/refman/5.0/en/views.html for the syntax on how to create views ho here : http://dev.mysql.com/doc/refman/5.0/en/create-view.html
-
If you are using database table views you will now need to create a specialised table class that specifies both the view table name and the base table name. For example :
class ComProfilesTableDepartments extends KDatabaseTableAbstract { public function __construct(array $options = array()) { $options['name'] = 'profiles_view_departments'; $options['base'] = 'profiles_departments'; parent::__construct($options); } } Added a $base parameter to the getColumns function to be able to retrieve the information from the base table, default is false. This only has effect is you are using table views.
1.1.3 Behaviors
-
Added KDatabaseTableAbstract::addBehaviors() function to allow adding behaviors at runtime. Added a 'behaviors' option to KDatabaseTableAbstract and a 'table_behaviors' option to KModelTable. Both options allow you to setup default behaviors for a table or model at object construction.
For the moment Nooku Framework does not implement any default behaviors. You are responsible for adding them yourself. You can do this in three ways :
In your model constructor :
class ComHarbourModelBoats extends KModelTable { public function __construct(array $options = array()) { $options['table_behaviors'] = array('lockable', 'creatable', 'modifiable'); parent::__construct($options); } }In your table constructor :
class ComHarbourTableBoats extends KDatabaseTableAbstract { public function __construct(array $options = array()) { $options['behaviors'] = array('lockable', 'creatable', 'modifiable'); parent::__construct($options); } }At runtime :
KFactory::get('admin::com.harbour.table.boats')- >addBehaviors('admin::com.foo.behavior.fooable');
1.1.4 Mappings
Added a KDatabaseTableAbstract::mapColumns function that adds column mapping support either to or from the actual schema.
-
Added column mapping support to KDatabaseRow. You can now setup column mappings. For example, if you want to map the database field 'name' to 'boat' :
class ComHarbourTableBoats { public function __construct(KConfig $config) { $config->column_map = array('boat', 'name'); parent::__construct($options); } }This allows you to abstract your actual data layer from your business logic layer. For example if your database schema changes and you still want to keep your models and views working you can implement mappings for the changes.
Another use case could be if you are adapting an legacy database to a new design, for example if you want to re-use a Joomla 1.5 table, but adapt it to new naming conventions used in certain behaviors.
For more info as to the reason and discussion behind this change please see : http://groups.google.com/group/nooku-framework/browse_frm/thread/b834...
1.2 KDatabaseSchema
Introduced a Schema subpackage which includes a KDatabaseSchemaField and KDatabaseSchemaTable class. Both classes are used to store field and table schema informtion and will later be used to cache the database schema information.
KDatabaseSchemaField also returns the native adapter type, to retrieve the filter (system type) you call KDatabaseSchemaField::getFilter instead of relying on the type itself.
KDatabaseSchemaField implements a virtual 'filter' property in favor of the setFilter and getFilter functions which have been removed. For example to get a table fields filter: KFactory::get('admin:com.foo.table.items')->getField('text')->filter;
-
KDatabaseSchemaTable stores it's behaviors in an associative array to allow easy checking if a behavior exists. For example :
//Get the table behaviors $behaviors = KFactory::get($row->getTable())->getBehaviors(); //Unlock the row if(in_array('lockable', array_keys($behaviors))) { $row->unlock(); }
1.3. KDatabaseBehavior
-
Database behaviors allow you to modify and or extend the way database tables deal with data. Database behaviors are different from filters in that they can do a lot more then just filter data. A database behavior can do the following 3 core things :
- Mixin methods with a row and rowset objects
- Act on table events (select, insert, update, delete)
- Act on database events (select, insert, update, delete)
We have 5 core behaviors : lockable, modifiable, creatable, identifiable and hittable You can find them in libraries/koowa/database/behavior.
Especially the lockable behavior is a good example of how database behaviors work.The lockable behavior is responsible for locking and unlocking rows, much like the checkout works in Joomla. To make this work KTemplateHelperGrid::id function has been refactored to accept a whole row object and deal with locking of rows. For an example implementation please see com_profiles.
-
Implemented conditional mixing of database behaviors and added a magic is[Behavior] function to KDatabaseRow(set) that allows client code to check if a behavior exists on a KDatabaseRow(set) object.
The conditional mixing of database behaviors can be implemented using the getMixableMethods function, for example for the Lockable behavior it looks like :
public function getMixableMethods(KObject $mixer = null) { $methods = array(); if(isset($mixer->locked_by)) { $methods = parent::getMixableMethods($mixer); } return $methods; }In this example we check if the locked_by property exists in the row object (taken any data mapping into account). If it exists we return the available methods for mixing, if not we don't return any methods at all. This technique allows you to let a behavior object decide if it want's to get mixed with a mixer and under what condiditions.
At the same time KDatabaseRowAbstract also implements and is[Behavior] magic function that allows client code to check if a certain behavior was succesfully mixed. For example in KControllerAction you will find the following code :
if($row->isLockable()) { $row->unlock(); }This code locks the row, only if it's lockable and if the layout is form. This way we are automagically implementing locking and unlocking of database rows and all your client code needs to do is define a table as lockable.
Added KDatabaseBehaviorIdentifiable. This behavior adds Universally Unique Identifiers (version 4) to your tables. For more info on UUID's please see : http://en.wikipedia.org/wiki/Universally_Unique_Identifier and also [http://debuggable.com/posts/why-uuids:48c906cc-7a6c-4f22-9e20-6ffd483...(http://debuggable.com/posts/why-uuids:48c906cc-7a6c-4f22-9e20-6ffd4834cda3) to learn why UUID are important.
The KDatabaseBehaviorAbstract::getHandle function now checks for the presence of one or more command handler functions. A command handler function needs to have a form of afterTable[Command] or beforeTable[Command]. If no valid command handler functions are found getHandle() will return NULL and the command will not be enqueued in the chain.
1.4 KDatabaseRow(set)
-
KDatabaseRow::save has been adapted to pass itself to KDatabaseTable::insert or update methods.
This way you can intercept and interact with a row object in the database behaviors, allowing you to make use of the data mapping. For examples, on how to use this when building database behaviors please see the core behaviors.
-
Added row and rowset modified state tracking. Both the KDatabaseRowAbstract and KDatabaseRowsetAbstract class keep track of the columns that are being changed.
When a row is saved only the modified columns will be saved to the database. This allows for better tracking of changed data through the database behaviors.
Added row states to KDatabaseRowAbstract. A row is now capable of tracking it's own state, supported states are 'inserted', 'deleted' and 'updated'. You can retrieve a row's state using the new getStatus function.
-
Implemented a 'new' property in KDatabaseRowAbstract that tracks if a row is new or not. The property can be set on row and rowset instantiation using the 'new' option. Default is true.
KDatabaseRowset::insert now also has a second 'new' parameter to track if the created row(s) need to be set as new, default is true. This change fully decouples row and rowset objects from a tables primary key. The row now decides based on it's new state if it needs to perform an insert or an update query.
Simplified the KDatabaseRowset::insert method to only accept a KDatabaseRow object. The constructor is responsible for converting the configuration data to row objects and inserting them.
Added identity column support to KDatabaseRowset. If the identity column is set the rowset will store it's internal data using and associative array where the key is the row's identity column. The find() function is now able to find rows based on the identity column values.
2. KModel
2.1 KModelTable
-
Set the limit and offset default to 0 in KModelTable. This change prevents that a LIMIT clause is added to any getList query. Limits now need to be specifically defined. Instead of defining a default limit of 20 in the state I have moved setting the limit to the ComDefaultControllerView::_actionBrowse function based and I'm using Joomla's list_limit configuration setting for better Joomla compatibility.
This change will make sure that if you call a model directly the limit will be 0 and no LIMIT clause will be added unless you speficically set the limit to a value. For example :
$result = KFactory::get('admin::com.harbour.model.boats) ->published(1)->getList();This will return all the published boats.
$result = KFactory::get('admin::com.harbour.model.boats) ->published(1)->limit(10)->getList();This will return the first 10 published boats.
Changed KModelTable::getItem function to return a default row object when no query was created or when no data was returned from the database.
Decoupled KModelTable from primary key. The getItem function now also calls _buildQueryWhere for increased flexibility. This could potentially lead to unexpected results in your code. Please double check and post on the list if you find an issue.
Changed KModelState and added 'unqiue' field to each state. Changed KModelState::insert function to be able to set if a state is unqiue or not. Added 'unique' parameter to KModelState::getData, if TRUE the function will only return states that are unique. Added a new KModelState::isUnique function to check of the state is unique or not.
Implemented new fetch mode in KModelTable::getItem and getList methods. Refactored getItem method to allow KDAtabaseTableAbstract::select to return an empty row object if no valid query information was passed.
3. KController
Renamed KControllerView to KControllerAction. The action controller is considered a specialised bread controller implementing the page controller pattern.
-
Implemented KController improvements based on suggestions from Cristiano as discussed in the following thread : http://groups.google.com/group/nooku-framework/browse_thread/thread/0...
You can now add an optional parameters array to the KMixinCommand::registerFunctionBefore and registerFunctionAfter. The parameters will be passed when the registered function is invoked.
For example $this->registerFunctionAfter('save', 'doSomething', array ('param1', 'param2'));Added KControllerAbstract::__call() to map functions to actions. For example you can now do
$controller = KFactory::get('admin::com.harbour.controller.boats'); $controller->browse(); instead of $controller->execute('browse');KControllerAbstract::getActions now also returns registered aliases.
This means that you now get a full list of all the actions available to a controller both the once that are defined as methods as the aliasses that are mapped. This gives increased flexibility and makes sure you always have all the information about the available actions.
This second change allows you to very easily build controller chains as Cristiano demonstrates in his post.
KControllerBread::_actionEdit() now returns a rowset instead of a row which allows edit actions to take place on multiple rows. All actions use
KRequest::get('request' , 'string')when setting state in the model. This covers more scenarios then using get or post specificallyAll KControllerAction actions are now wrappers for the BREAD actions of the parent controller.
-
Added a displayView method to KControllerBread. By default the method is triggered after a browse and read action. This can easily be changed by unregistering the method or registering it after other actions. For example :
class ComFooControllerItem extends ComDefaultControllerView { /** * Constructor * * @param array An optional associative array of configuration settings. */ public function __construct(array $options = array()) { parent::__construct($options); // Register command functions $this->registerFunctionAfter('foo', 'displayView'); } }This can be handy if you want to display a view after a none-get action like browse or read.
-
KControllerBread::actionBrowse now returns a KDatabaseRowset object and KControllerBread::actionRead now returns a KDatabaseRow object
This change is needed to allow you to easily gain access to the domain objects to perform actions on them, like lock, unlock etc. Those actions will be mixed in using the new KDatabaseBehavior objects which.
-
The KController changes require you to explicitly set the form action to browse if you are adding POST filters to your grid views. For example :
<form action="<?= @route()?>" method="post" name="adminForm" class="form-grid"> <input type="hidden" name="id" value="" /> <input type="hidden" name="action" value="browse" />See also the default.php template in adminstrators/com_profiles/views/people/tmpl/
Moved token check into the execute function in KControllerAction to force token validation for all POST requests
KControllerAction::cancel action now calls parents actionRead retrieve the row object. It does not go through the command chain to prevent issues with post and pre functions on the read action.
Added a $data parameter to KControllerAbstract::execute(), KControllerBread::edit() and KControllerBread::save() functions. If no $data paramater isset KControllerBread::execute will retrieve it from the KRequest. The $data parameter allows you to more easily setup controller chains.
Enable and access actions now push the data directly to the edit function instead of going through the Request set method. Making use of the new $data parameter.
Renamed KContollerBread::loadModelState to getRequest. Added setRequest function to allow (re)setting the request and a new $_request property to encapsulate the controller request information.
Added KContollerBread::setRequest function to allow (re)setting the request and a new $_request property to encapsulate the controller request information.
Renamed KControllerBread::saveState to saveModelState. The getRequest() function is now called before any BREAD action is executed and loads the state from the request into the model. This changes makes it possible to use the model as a state store.
-
Decoupled KControllerView::actionSave and KControllerView::actionApply from the request 'id' variable and implemented KModelState::isUnique to check if we need to perform an 'edit' or an 'add' action.
These changes make the controller alot more flexible because we decoupled it from 'id' you can now load any row based on a unique column in that database which opens up some interesting new possibilities.
The changes where triggered by the following discussion : http://groups.google.com/group/nooku-framework/browse_frm/thread/efde...
Moved the KControllerAbstract::getView, setView, getModel and setModel function to KControllerBread. This changes make the abstract controller more flexible and brings the bread controller closer to the correct implementation of the page controller pattern.
4. KDispatcher
Did a bunch of work on KController and KDispatcher improvements to solve an issue with redirects after AJAX requests as reported by Cristiano in this thread : http://www.google.com/url?sa=D&q=http://groups.google.com/group/nooku...
Added identifier setters to KDispatcher::setController and KController::setView and setModel. For example, you can now do
KController::setModel(KFactory::get ('admin::com.harbour.model.boats));To manually set the model attached to a controller.Added KDispatcherDefault:forward() to deal with forwarding after a POST method. This change implements fluent request forwarding, either a RAP (redirect after post) on regular requests or a subsequent read/ browse action on AJAX requests.
KDispatcherAbstract now extends KControllerAbstract. Disptach and forward functions are implemented as controller actions. This changes makes the dispatcher adhere more closely to the implementation of a front controller pattern.
5. KMixin
Renamed getMixinMethods to getMixableMethods and added a mixer function parameter that allows to do selective mixing.
The getMixableMethods now only returns public methods. Previously it also returned non public methods which could result in strange behavior as non public methods cannot be mixed.
Added magic get, set, isset and unset methods to give direct access to mixer public properties from inside the a mixin. This allows for a more fluent interfacing of a mixing with a mixer.
Implemented a dynamic selective mixin pattern. In short this allows an instance of a mixin to be selectively mixed with multiple mixers (a mixer needs to be a KObject derived class). The mixin can decide which functions it makes available to each mixer based on the mixers instance type.
Decoupled the mixin from it's mixer. The mixer can now be dynamcially be set using the magic getters and setters.
Removed mixins dependency on KObject, KMixinAbstract no longer extends KObject, to disallow mixin-in a mixin, which does not make sense anyway. Mixins are considered a special base object type.
Implement a method cache in KMixinAbstract to reduce the amount of calls that are being made to the Reflection API for dynamic mixins.
KMixinAbstract. Added a magic __call function to direct mixin calls to the mixer if one exists. Together with previous changes this makes a mixin fully blend in with it's mixer in a dynamic way.
6. KFactory
-
Changed the 'factory' method that is being called by KFactory component and koowa adapters to 'instantiate' to follow naming conventions for action functions. The 'instantiate' function can be used for specialised instanciation of objects through the factory, for example :
KDatabase::instanciate is a specialised instantiator that deals with the creation of database adapters. You can also use this in your own classes to specialise the instantiation of your own objects or to force your objects to be real signletons.
Added behavior alias mapping to KFactoryAdapterComponent. If you want to create your own custom behaviors just put them into a behaviors folder in your own component and use the following identifier :
[application]::com.[component].behavior.[name], where application is preferably 'admin' and name is the name of the behavior. For example of behaviors see koowa/database/behavior.
7. KFilter
-
Added a static KFilter class that implements the instantiate method to allow easy creation of filter chains from an array of filter names and/or identifiers. For example you can now do :
$filters = array('html', 'tidy', 'custom'); $filter = KFactory::tmp('lib.koowa.filter', array('filter' => $filters));This will create a chained filter for you. This is primarily usefull in your programming logic if you want to create a filter without explicitly knowing what the filters will be you will be using beforehand.
8. KCommand
Added a KCommandChain::getContext function it returns a new context object if it does not exist, if the chain is running it will return the active context object.
-
Made a number of improvements to KCommandchain and the command handling. This is a list of changes made :
Added a new 'auto_events' option to KMixinCommandchain. This option is set the true by default, when set the false the KCommandChain will not enqueue a KCommandEvent and thus not send events. Setting this to false is adviced for commandchains that don't need to send out events to improve performance.
Added extra checks to KCommandchain to only enqueue command if they return a valid handle. This change allows for conditional enqueuing of commands. A command can override it's getHandle() function and based on it's internal conditions decide to return a valid handle or return null, if it returns null the command will not be enqueued.
-
Added priority constants to KCommandChain to make priority handling more declarative, supported constants are :
- PRIORITY_HIGHEST;
- PRIORITY_HIGH;
- PRIORITY_NORMAL;
- PRIORITY_LOW;
- PRIORITY_LOWEST;
Changed default priority of the event command changed it to 5 (lowest priority) in KMixinCommandchain. This to make sure that all other commands are ran first before an event is send. I also implemented changes to KDatabaseBehavior to improve conditional enqueing of commands in a tables commandchain using the changes made above.
KCommandContext now extends from KConfig instead of ArrayObject for consistency. Take note that if you are using KCommandContext you will need to change your code from
$context['x']to$context->x.
9. KObject
Added KObject::getMethods function to return a list of all available public object methods, both native and mixed in. Also changed all instance of method_exist in the framework to use getMethods. This change makes it possible to mixin and have the methods available in the mixin be recognised by the mixer.
Added a getMixedMethods function to KObject to easily interrogate an object about the methods that are being mixed in.
Major changes to overall identifier handling. Changed the KFactoryIdentifiable interface to KObjectIdentifiable.
Code cleanup of KObjectArray and removed the KObjectArray::unique function.
10. KConfig
Major changes to overall configuration handling. Added a new KConfig package and changed KObject::__constructor to only accepts a KConfig object instead of an array. If your code is overriding or specialising the framework your code will likely break.
Have a look at your parents class constructor In most cases all you will need to do is change
$options['foo'] = 'bar';to$config->foo = 'bar';.
11. KRequest
KRequest is now implemented as a singleton.
Renamed function raw() to content(). It returns an associative array with the content 'data' and the 'type' information.
-
Added content type negotiation to the KRequest::constructor for PUT and POST request. Supporting both
application/jsonandapplication/x- www-form-urlencodedcontent type.Json data is automatically converted to an associative array and pushed into the $POST array. Form url encoded data is parsed using parse_str and also pushed in the $POST array, this only happens for PUT as PHP does this automatically for POST requests.
12. REST
You can now use both POST and PUT and you can push in both
application/x-www-form-urlencodedasapplication/json data. The data will be converted on the fly and made available through the $_POST global which you can access usingKRequest::('get.foo', 'filter');.-
You can use the following methods to create REST requests :
You can use pure GET, POST, PUT and DELETE methods. PUT will be mapped to the 'edit' action, while POST will be mapped to the 'add' action in KControllerBread.
You can use POST and
X-HTTP-Method-Override, set it either to PUT or DELETE. This technique is standardised and avdised if you want to make your code compatible with all server. Some server block PUT and DELETE requests. If you are working only on your own server you can use 1.Finaly, you can use POST and action=x. This allows you to execute any action in your controller. This method is usefull if you want to define extra actions, for example as we do in our KControllerAction. That's it.
For more info please see http://nooku.assembla.com/spaces/nooku-framework/tickets/113-basic-re...
13. Other
Added a lcfirst function to koowa.php to solve backwards compatibiltiy issue with PHP5.3 which has a lcfirst function. If more compat functions are added I will likely move them to a seperate file.
Merged the code from ComDefaultViewCsv into KViewCsv. Csv views now work out of the box. All you need to do is add
format=csvto the url.