Overview of what Knop is
Knop is a web application framework for Lasso Professional, consisting of a number of core components implemented as custom types, and a defined application flow and folder structure.
An application framework saves time so the developer can focus on the core value of the application instead of dealing with the common and tedious repetitive tasks.
It allows for reusable code, components and modules.
Framework components become well tested over time which leads to higher quality of the application and reduces the risk of errors.
It leads to easier maintenance - changes and improvements can be implemented once and are immediately available wherever the component is used.
Using an application framework should lead to higher productivity and shorter lead times.
"Knop" is Swedish for knot, and a knot is what keeps a lasso together. A good knot makes a good lasso experience. And as a coincidence, "knop" in Swedish also has the nautical meaning just as knot has.
Knop is pronounced with a sounding "k" and a long "o" just as in groove. By the way, we reserve the use of the word "Ponk" as well just in case we find the need of the reverse of a framework, whatever that might be.
Knop is created by Johan Sölve, Montania System AB
Greg Willits' PageBlocks manual has been a valuable inspiration when specifying some of the components of Knop.
The framework is entirely based on a onefile structure.
Let's assume the user submits a form. Every page request has two vital parameters:
So to handle a form submission:
A) Take care of the input
B) Prepare the output
index.lasso _config: cfg__global.inc cfg__nav.inc cfg_cust_edit.inc cfg_cust_list.inc _action: act_cust_edit.inc _library: lib_cust_edit.inc lib_cust_list.inc _content: cnt_cust_edit.inc cnt_cust_list.inc
This is what Knop started with over a year ago and is the most mature of the components. The basic idea is that forms are one of the most tedious things to handle manually in a web application. First the form fields should be shown on the edit page. They need labels, proper styling and different properties. They also need initial values to show in the form fields. The values can either come from a database lookup, or from a previous submission of the same form if there was an input error that needs to be corrected, and in that case the erroneous fields or labels needs some highlighting to guide the user. And finally the form submission must be handled by validating the user's inputs and then storing the form data in a database.
All these tasks are a perfect target to make things easier for the developer.
First we define the form. We give it a form action, and we add the fields and other elements such as submit buttons that the form should contain. The fields can have the same properties as regular html form fields do, and they have additional properties to define the options of a select menu, the checkbox options of a checkbox field set, for interaction with databases and other purposes.
Then we fill the form fields with data. It can either come from a form submission or from a database lookup. In the case of a database lookup, the corresponding database field has been declared as property for each form field.
Then we set a template for the form to define how the form should be presented in html. Or we can just use the default template.
Then we render the form on the page. We can render the entire form at once, or specific fields at a time (we can even set different templates for every field), to have the flexibility needed to able to accommodate the form in just about any html context.
The next step is that the user submits the form. Now the form object makes its second entry by taking care of the form submission. Since all form fields are defined in the form object, it knows where to put each field when we tell it to load data from the form. And since it knows what kind of data is allowed in each field the form object can validate itself with a single call.
If the validation encounters an input error, the form objects prepares to show itself again but this time with the erroneous inputs highlighted.
If the validation passed, the form object comes back to our help once again and provides us with a complete pair array with field name and value pairs (the form fields knew what database fields they correspond to, remember?) that we can feed right into an inline to add or update a database record, or we can get an SQL string that we can put in a SQL statement of our liking.
Example member tags of knop_form:
-> addfield -> setformat -> renderform -> loadfields -> validate -> updatefields
When defining the form object we can even give it a reference to a database object, and if we do that then the real magic begins. Now we can just tell the form object to "process" and it will do the right thing with the database, be it add, delete, or update. Just one line of code.
That leads us to...
This is a core data type to handle add, update, delete, select with optional record locking (pessimistic locking with timeout). It can handle duplicate prevention to avoid adding a record again if the user reloads the submitted page. It generates key values in the form of random strings in the database, to use as "safe" key values.
knop_database primarily uses pair arrays as field specifications, which makes it easy to integrate with standard Lasso inlines, but can also use sql statements for some of the operations. When interacting with knop_form and knop_grid, pair arrays are normally used to exchange field data and other search parameters. The use of pair arrays for standard inlines is one way to provide greater flexibility.
knop_database works transparently both with SQL (primarily MySQL) and FileMaker databases.
Example member tags of knop_database:
-> select -> getrecord -> addrecord -> saverecord -> deleterecord
The result of a select operation (to get multiple records, as opposed to getrecord which gets a single record) is available to the page as a standard inlinename record set, or a records_array. Select supports true found_count even when using LIMIT with raw SQL statements. knop_database can interact with knop_form and knop_grid.
This custom type is for showing record listings with pagination, sorting, edit link etc. It requires a reference to a database object because they are so tightly related. It can highlight the affected record when returning to the list after adding or editing a record. We can also give it a reference to a nav object, to get the right pagination links and other things. It can also provide a basic "Quicksearch" function integrated with the record listing. Quicksearch and the sort headings generate pair arrays (or sql strings) to interact with knop_database. Sort parameters and the quicksearch query is automatically propagated through a form, so the same set of records set is selected after editing a records.
Example member tags of knop_grid:
-> insert (to add list columns) -> sortparams -> renderhtml
This data type keeps track of where the user is and where he can go, and validates that a user is allowed to access the current location. It is responsible for displaying the navigation menu and gives us some tools to include the right config, action, lib and content files. The navigation menu is as default rendered as a hierarchical ul/li list, which can be styled as horizontal top navigation, left or right navigation, as tabs, indented lists or whatever. Only css sets the limit.
knop_nav supports both parameter based navigation, where the current location is specified as url parameter "?-path=", as well as "URL design"-style navigation based on the URL path, where the current location is the path (for example using an atbegin url handler). knop_nav supports navigation hierarchies in multiple sub levels with arbitrary depths. knop_nav doesn't have to define the navigation for an entire site, it can restrict itself to a section of a site (a sub folder for example)
Example member tags of knop_nav:
-> insert -> getlocation -> renderhtml -> renderbreadcrumb -> include
knop_nav can interact with knop_grid.
This custom type handles language strings for multilingual presentation of the user interface. A knop_lang object holds the language strings for all supported languages. Strings are stored under a unique text key, but the same key is of course used for the different language versions of the same string.
Language strings can be grouped into different knop_lang object instances (variables) if it helps managing them.
When the language of a knop_lang object is set, that language is used for all subsequent requests for strings until another language is set. The selected language is shared between all knop_lang objects on the same page for that visitor, unless another language has been set specifically for an individual knop_lang object.
If no specific language is set on the page, knop_lang uses the browser's most preferred language if it's available in the knop_lang object, otherwise it defaults to the first language (unless a default language has been set for the knop_lang object).
The strings in a knop_lang object can contain replacement placeholders, to be able to insert dynamic text when retrieving a string. The strings can also be a Lasso compound expression which will be evaluated at runtime when the string is retrieved. Examples
$strings_messages -> loginfailed; $strings_errors -> recordlocked; $strings_info -> (setlanguage: 'sv'); $strings_info -> welcome; $strings_info -> (setlanguage: ($strings_info -> browserlanguage));
The Knop_user custom type handles user authentication, maintains information about the user and keeps track of permissions for the user.
Authenticating a user checks the login credentials against a specified table, with support for one way encrypted passwords (with salt) and delays between repeated login attempts to prevent brute force attacks. User authentication can also be performed through custom code outside of Knop_user.
Knop_user prevents session sidejacking by comparing a client fingerprint between each page request. Knop_user is the only Knop custom type that is intended to be stored in a session variable, and actually relies on this.
When a user is being authenticated, all available fields from the user table are stored in the Knop_user variable so user information can be retrieved easily throughout the session. Any additional custom data for the user can also be stored manually in the Knop_user variable.
Knop_user can keep track of user permission by storing arbitrary permission information in the Knop_user variable. Knop_user enhances Knop_database objects by keeping track of record locks set by the user, and releasing record locks for example when navigating to a list of records without saving an edited record.
Official project home page: http://montania.se/projects/knop/
Downloads, documentation and code repository: http://code.google.com/p/knop/
Online API reference: http://montania.se/projects/knop/help.lasso
Online demo: http://knopdemo.montania.se/
Knop presentation slides at LDC Chicago 2008: http://www.slideshare.net/macsolve/knop-framework-presentation
Knop presentation video: http://video.google.com/videoplay?docid=-5160119806122202429&hl=en#
Author: Johan Sölve
Created: 12 Oct 2009
Last Modified: 16 Mar 2011
Please note that periodically LassoSoft will go through the notes and may incorporate information from them into the documentation. Any submission here gives LassoSoft a non-exclusive license and will be made available in various formats to the Lasso community.