Lasso Soft Inc. > Home

  • Articles

Knop Framework 

Overview of what Knop is 

Knop introduction

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.

Why framework?

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.

Why "Knop"?

"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.

Goals with Knop

  • A lightweight and easy to use framework, mainly targeted for web based applications (as opposed to web sites).
  • Flexibility to allow for special needs case by case.
  • Encourage the use of modern standards-based and semantically correct html and css for presentation.
  • Use client side scripting as progressive enhancement to improve user experience and application responsiveness, but do not rely on client side scripting for critical functionality.
  • Use Ajax techniques where really motivated

What is Knop?

  • A defined application flow, to handle page requests, respond to form submissions and show the resulting page
  • A defined folder structure to handle the application logic
  • A number of custom types that handle the cure functions of the framework:
  • knop_form - a form generator
  • knop_nav - handles navigation in the application
  • knop_grid - handles record listings
  • knop_database - handles database interaction
  • knop_user - handles user authentication and authorization
  • knop_lang - handles user interface strings for localization
  • Basic templates for html and css

The framework is entirely based on a onefile structure.

Application flow

Let's assume the user submits a form. Every page request has two vital parameters:

  • action path (optional), this tells the application how to act upon a submission (if there is one). In other words, where we came from. (This is not to mix up with the 'action' html attribute of the form tag itself, that is a completely different thing.)
  • path (required), this tells the application where to go next.

So to handle a form submission:

A) Take care of the input

  1. Find out 'action path', which is where the submission comes from (this is determined by knop_nav)
  2. Load config for the action path to define forms etc.
  3. Run action to load form data, validate input and run all the logic needed in response to the form submission if validation is ok

B) Prepare the output

  1. Action ok? -> Load config for 'path' to define form, grid etc for display
  2. Action not ok? -> 'path' is set to 'action path' (config does not need to load again)
  3. Run lib for 'path' to prepare the page output
  4. Include template to build the page html framework with navigation menu, content area, sidebars etc.
  5. Template includes content for 'path' to assemble the actual page contents
  6. Page is served to browser.

Folder Structure


Knop custom types

Custom Type: knop_form Form Generator

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 form object even generates some javascript for us that will warn the user if he navigates away from a "dirty" page (a page that has unsaved changes) and other nice features.

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...

Custom type: knop_database for Database Interaction

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.

Custom type: knop_grid for Database Record Listings

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

Custom type: knop_nav Site Navigation

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.

Custom type: knop_lang for Language Strings

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));

Custom type: knop_user for User Management

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.



Code examples


Official project home page:

Downloads, documentation and code repository:

Online API reference:

Mailing list archive

Online demo:

Knop presentation slides at LDC Chicago 2008:

Knop presentation video:

Author: Johan Sölve
Created: 12 Oct 2009
Last Modified: 16 Mar 2011


No comments found
You must be logged in to comment.

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.

LassoSoft Inc. > Home



©LassoSoft Inc 2015 | Web Development by Treefrog Inc | PrivacyLegal terms and Shipping | Contact LassoSoft