Konstrukt Reference

This document contains a description of the features of Konstrukt. For a more hands-on introduction, you should start out with getting started.

There is also an autogenerated api-reference, which contains all classes, interfaces and methods in the library.

If you find any errors - even if it's just a spelling mistake, or a dodgy phrasing - don't hesitate to tell about it.

Troels Knak-Nielsen, January 2009, troelskn@gmail.com

Component essentials

A component is a class that extends from k_Component. Its purpose is to handle a request or delegate control to another component, that can handle it. This is much similar to how the Apache web server is structured. The way a component is addressed is through the URL path. Each path segment is mapped to a component. The special thing about Konstrukt in this respect, is that the exact mapping is determined at runtime. Each component is fully responsible for choosing the next component in the chain. This is a very powerful concept, but can also be slightly hard to comprehend at first. As a newcomer you may therefore find the dispatch logging useful.

Dispatch life-cycle

A component is instantiated as an object before use. To allow for maximum flexibility in implementation, the constructor is not used for passing essential dependencies. These are instead passed immediately after creation through setters. Of these dependencies, the most important is the context, which will usually be another component instance.

As a developer you have great control over the creation of components. You can read more about this in the section on component creation.

Handlers

Components can implement a number of fine grained methods to provide functionality. As a developer, you'll normally just implement/override a few of them, but if you need to, you can override them all, thereby hooking into the core workings of the framework. In particular, you will often implement renderers and input handlers, as well as map() and in some cases dispatch(). If you find your self overriding any of execute(), render(), GET(), POST(), PUT() or wrap(), it should be a warning sign that you are doing some thing wrong; These all default to delegate control to more specific handlers and as such you usually wouldn't have to override them.

Dispatch

Once the component is instantiated, the context will delegate control to the component, by invoking its dispatch() method. dispatch() inspects the remainder of the path (the subspace) and does one of two things: If the path contains any further names, it will call map() with the next name, and receive a corresponding classname. It will then instantiate this component, becoming the context, and dispatch to it. If there is no further names (it is the final component), it will handle the request.

While you can hook in to various places in the request handling, the most common is to implement a renderer - typically renderHtml(). Since you're application will presumably contain more than one component, you will also get acquainted with the map() method.

Some times, a request can contain a message-body - The typical case being a POST'ed web-form. To handle this, you'd implement an input handler postForm().

The already mentioned dispatch() method can be overridden to put code that should execute for all types of requests to the component. It is typically used for access-control/authentication and for checking the existence of the resource (throw a k_PageNotFound if not). If you override this (or other) handler(s), remember to call the parent implementation at the end. Eg.:

class MyComponent extends k_Component {
  function dispatch() {
    if (!$this->model->find($this->name)) {
      throw new k_PageNotFound();
    }
    return parent::dispatch();
  }
}

Some times, a request can contain a payload (Known as the message-body). This is only allowed with POST and PUT types requests - the typical use-case being a <form> being submitted through POST. To handle this, you will have to implement a handler matching the request-type and the content-type of the request. For example, to handle a regular form, you would implement postForm(). Another, slighty less common, handler would be postMultipart(), which would be used if the form contains file uploads. You can read more under the section input handlers.

Renderers

Most components have a way to render themselves. When a regular GET request is issued to the component, it will try to render it by calling a so-called renderer. Renderers are simply methods that are prefixed with render and followed by a short-name corresponding to the content-type that they provide. For the majority, renderHtml() is the most common renderer, but you can implement other content-types such as renderJson() or renderRss(). If a component provides multiple renderers, it will pick one based on the Accept header of the incoming request. This means that the client (usually a browser) can decide which format it prefers. This is a feature known as content-type negotiation, because it happens automatically based on the clients preferences and the available formats.

Some times you may need to have a URL refer directly to a specific representation (content-type) of a component - In this case, you can postfix the URL with the content-type short-name. For example, the URL /foo/bar is subject to content-negotiation, while /foo/bar.csv will only render through renderCsv() (Of course provided that this method is implemented).

Subviews

Some times you need to be able to display alternative views of the same resource + content-type. The most common example is for forms. A url like /superheroes/batman might show a html page for the dark knight, but which url should be used to edit the stats for him? One option is to use a sub component, as in /superheroes/batman/edit, but this suggests that edit is a resource under batmna, when it is really just another representation of it. A place where this causes trouble, is if a component has children. For example, /superheroes/create might be a form for creating a new entity, but it could also refer to an entity named create.

To deal with these issues, Konstrukt provides a concept called subviews. If the url contains a parameter without any value, following right after the question mark, it will be used as a suffix to the render method. For example, /foo/bar.html?edit will resolve to renderHtmlEdit, if defined. Again, the content-type may be left out, so that /foo/bar?edit resolves to the same handler.

To have a subview, there must be a primary view. Eg. you can't have renderHtmlEdit without having renderHtml.

Note that the subview parameter is also a query-string parameter, so it will turn up in query().

Return type

The return type of a renderer depends on the content-type it handles. It is always valid to return an instance of k_Response, but most of the time you should just return a language primitive (such as a string for renderHtml()) and it will be wrapped in an appropriately typed response instance. The primitive type to return depends on the content-type. This type is also called the internal type, and it is the same type that will be passed to any wrappers. The supported internal types can be read from this chart:

content-type short name internal type(s)
text/html html string
text/plain text string
application/json json any scalar, array
application/x-serialized-php php anything that can be serialized
text/xml xml string, DomNode, SimpleXMLElement

Other HTTP-methods than GET may also render an output. To do so, you can call render() from within the handler, and it will then delegate to the appropriate render-method. (This is what GET() does behind the scenes). For example, you might end your postForm() method with the line:

return $this->render();

Note: The content-type of renderers is based on the Accept header of the request, and defines the type of response that goes out. Certain requests (notably POST and PUT) may have a different content-type, specifying the type of the message-body. This is handled by a related, but different mechanism called Content-Type delegation

content-type short-names

There are various places where content-types are referred to through their short-names. For example, renderers are named according to the content-type they provide. So are input handlers. There are many content-types, but the most used ones are depicted in the table below:

content-type short name render method
text/html html renderHtml
text/xml xml renderXml
text/plain text renderText
text/csv csv renderCsv
text/x-vcard vcard renderVcard
application/atom+xml atom renderAtom
application/calendar+xml xcal renderXCal
application/rdf+xml rdf renderRdf
application/json json renderJson
application/pdf pdf renderPdf
image/svg+xml svg renderSvg

You can add your own content-types to the global array $GLOBALS['konstrukt_content_types'] as follows:

$GLOBALS['konstrukt_content_types']['test/html'] = 'html';

If you're adding a generic content-type, you might want mention it to the developers, and we'll try to incorporate it in the main library.

Input handlers

The HTTP-methods POST and PUT are special in that they contain a message-body. The content-type of this payload is specified in the requests Content-Type header.. To distinguish between them, the default implementation of POST() and PUT() will try to dispatch to a handler corresponding to the requests content-type. For example, a regular posted form has the application/x-www-form-urlencoded content-type. This will be delegated to postForm(). A request of the type application/json will be delegated to postJson(). This feature, which is known as content-type delegation, allows you to implement support for different content-types in a standard fashion.

The naming of the content-type handlers corresponds to their short-names, but the most commonly used are depicted below:

content-type POST handler PUT handler
application/x-www-form-urlencoded postForm putForm
multipart/form-data postMultipart putMultipart
application/json postJson putJson

This mechanism is somewhat similar to content-type negotiation, but differs in that render() relates to the Accept header - Which has to do with the output-format of the HTTP-response - while content-type delegation relates to the Content-Type header - which has to do with the input-format of the HTTP-request.

Wrappers

When a component delegates control to a sub-component, it can some times be useful to decorate the response. A typical case is to render navigation or to render the <head> tags in the root component. While you could manually override dispatch() or forward() to do this, there is already a mechanism in Konstrukt called wrappers. Wrappers are typed just like renderers and they are picked according to the content-type of the sub-components response. This means that wrapHtml() will only apply to sub-components that return a html-response. There is a special hook for intercepting un-typed (k_HttpResponse) responses, which is renderHttp(). It is rarely used, but if you need it, it's there.

A wrapper takes a single argument, which is the internal representation of the response to be wrapped. Like the renderers, wrappers can either return an instance of k_Response or just return the internal preresentation, which will then be converted to a typed response automatically.

Other handlers

As already mentioned, there are a few other handlers which can be implemented in your components. If you want to support all the major HTTP verbs (HEAD, PUT, DELETE), you can do so by implementing the correct handler. For handling HEAD and DELETE, simply implement a method named HEAD() and DELETE() respectively. The PUT method follows the pattern of POST, so you shouldn't implement PUT(), but rather a handler specific to the input type; Eg. putForm or putJson etc.

HTTP input

A component can access the various inputs that comes from a http-request. These are obtained through the $context object, rather than through a global place, which makes components very encapsulated and - among other things - more testable.

Note that all these properties are accessed through methods, not as fields. So you would refer to $this->name() rather than $this->name

name, subtype, subspace

Initially the most important input is probably the name. This returns the part of the url that this component belongs to. For the last component of the url /foo/bar/quux, the name would be quux. This property is often used as a primary key for identifying the underlying resource.

The subtype property is the part of a path-segment that comes after the name, delimited by a dot. It's used internally to identify the content-type. As a developer you'll probably not need to access this very often.

The subspace property contains the remaining part of the path, for a component that isn't the last in the dispatch chain. For example, given the component identified as bar in the url /foo/bar/quux, the subspace would be quux. This property is also rarely used directly.

query, body

In addition to the url/path, there are two important input sources; The query-string and the request body. In plain PHP, these are available through $_GET and $_POST respectively, but in Konstrukt they are accessed through query() and body(). This naming is more precise, in that query-string parameters aren't just for GET requests, and a request body can come with other kinds of requests than a POST.

You can call the accessors without any arguments and get a hashmap back, or you can provide a name, and just get the value for that field. If the key isn't set, you will get back null, rather than a warning.

  $this->query(); // array('foo' => 'bar')
  $this->query('foo'); // 'bar'

You can also pass a default value that will be returned if the specified key doesn't exist.

  // /baz?grault=waldo
  $this->query('foo', 'bar'); // 'bar'

The renderer operates with the concept of subview. This is simply a query-string parameter without any value. In a url like /foo/bar?quux, the subview would be quux. This property is used to determine the appropriate renderer. While the value could occur anywhere in the query-string, it is usually placed as the first element, right after the question mark.

Querystring namespace

Because the querystring is shared amongst every component, you can sometimes run into problems when you need to pass parameters to multiple components (Not exactly a common requirement, but it can happen). Components can use a namespace to protect the querystring in these cases. It's the context that specifies a namespace for its subcomponents, and it works completely transparent to the subcomponent. To create a component with a namespace, your map() method should return an array instead of a string, where the first element is the namespace and the second is the classname.

Session

Sessions are a very powerful feature for maintaining state in a web application. Unfortunately it's often overused. While there are cases where it's the best pick, you should generally try to use some other means of maintaining state, if at all possible. That said, Konstrukt provides access to PHPs session mechanism, through a wrapper.

Each component has a method session() that can be called in two ways. Either you provide an argument (Which should be a string), and you'll get the value of a session variable by that name back (or null, if it's not defined). Alternatively you can call it without any arguments, in which case you'll an object back of the type k_adapter_SessionAccess. It has methods for getting/setting session variables and other session-related functions.

Note that you don't need to worry about calling session_start(), since this is done automatically by the wrapper.

Cookies

A cookie is a mixed client/server side way of maintaining state. It has a number of limitations which makes it a less popular choice, but it can still be useful in certain cases. You can access cookies through a wrapper in Konstrukt.

The cookie wrapper works just as the session wrapper. Each component has a method cookie() that can be called with a parameter to retrieve the value of a cookie by that name, or without any arguments to get an object back of the type k_adapter_CookieAccess.

File uploads

In PHP files uploaded with a form are accessible through $_FILES. Inside a component, you can access the same information through the method file(). You can either pass a parameter to get back a specific file or call it without any arguments to get a hashmap of all files. A file is wrapped in an object of the type k_adapter_UploadedFile, which helps to abstract direct access to the filesystem away. As a side effect it also has a simpler interface than PHPs native handling of file uploads. To save an uploaded file, just call writeTo($path_destination) with the destination as argument.

Note that you need to go through the regular hoops to get file uploads working. Most importantly you need to set the enctype="multipart/form-data" property on your form tag. When you do this, the handler for processing the form will be named postMultipart(). (See input handlers for more details).

Url generation

All components are tightly coupled to a url. Components can parse (dispatch) urls, and they can also generate urls. To make your application as flexible as possible, it is recommended that you generate internal urls, using the url() method, rather than hardcoding them as strings. From within a component, you can call url() without any parameters to get a url pointing to the current component. As the first argument, you can pass a subspace, and as the second argument, you can pass a hash of query-string parameters. Eg.:

   $this->url('foo', array('bar' => 42)); // -> /url/for/this/component/foo?bar=42

Generating urls this way, makes it easy to move components around without having to make any changes to the view.

Note that the first argument isn't automatically encoded. You can optionally pass an array of strings instead. These are then encoded and joined with a path-separator (A slash). Eg.:

   $this->url(array('foo', 'quux'), array('bar' => 42)); // -> /url/for/this/component/foo/quux?bar=42

Note: Apache has a security feature that disallows url path segments to contain an encoded slash. Thus, you should avoid names that contains slashes. In general, it is a good idea to stick to a-z0-9_- for url names.

Urlstate parameters

If a component needs to maintain view-related state, you have a limited set of options. In essence, the choice is between propagating state over urls (client side state) or using a server side mechanism (eg. sessions). Cookies are also a solution, but it has most of the problems associated with session state, and even some of its own. Client side state is often the superior choice, but it is tedious to do by hand. Konstrukt has therefore a mechanism builtin to support this. Viewstate can be propagated as querystring parameters, using the urlstate property of a component. Properties that are set on the urlstate will be automatically set on any urls for the component, unless explicitly overridden. A typical usecase is for searches and other data-views.

Urlstate parameters are specified, along with their initial value, by implementing the url_init in your component. For example, to the following specifies a single parameter "foo". If no input is present for it, it has the value "bar":

class MyStatefulComponent extends k_Component {
  protected $url_init = array('foo' => "bar");
}

If a urlstate parameter is passed on the querystring, it will automatically override the urlstate containers value. Eg. for a request with the query-string ?foo=quux, the following would yield "quux":

  $this->url_state->get('foo'); // -> "quux"

Shared objects

A few objects are shared amongst all components.

Identity

The identity object is an object represeting the current user. Every component can access the identity by calling the access identity(). The default implementation is k_Anonymous.

The identity is loaded from an k_DefaultIdentityLoader, that can be configured with the bootstrap. An identity-loader is a simple factory, that gets passed the top-level context, and is expected to return an instance of k_Identity. The usual use case is to load a user-object from the database or an authentication system.

Document

The document is an instance of k_Document, and contains values that are global to the HTML document, such as title, CSS includes etc. A component can access the document via the document() method.

The default document has accessors for setting the title, adding external javascript and Css files to <head>, and adding javascript code to run on page load. This is a fairly limited number of properties. If you need more, you could subclass k_Document and set your own implementation in the bootstrap. It is recommended to keep such properties as specific as possible, to prevent that the object becomes a dumping ground for global variables.

Abnormal responses

Untyped responses

By default, components are expected to return either an instance of k_Response or an internal type, that is then converted. While you would usually want to return a response that matches the expected type (Eg. a k_HtmlResponse from renderHttp() etc.), you can return other types. A common reason to use this, is to respond with a redirect.

There are three specialised responses (all types of k_Response) that should be used for redirects:

k_MovedPermanently
Use this if the URL has changed (Eg. a page has been renamed).
k_SeeOther
Use this type of redirect specifically for redirecting after POST.
k_TemporaryRedirect
Use this type of redirect if the destination changes from request to request, or if you want the client to keep using the requested URI in the future.

These all take the target URL as argument for the constructor.

Meta response

A meta response is not really a response. It is a type of exception, that can be caught at the top-level dispatcher and there turned into a component. Other frameworks deal with this through internal redirects, and you could think of it as such. You should use meta responses for a number of specific error-states that can occur in your application.

While you could just return a http response, the meta response adds a level of indirection that can be useful at a later point. The primary benefit of using a meta response over a http response, is that it gives you control over rendering of various error-pages. For example, rather than constructing a http response with status 404, you should use the meta response k_PageNotFound. This makes it possible to have a customised page for all "not found" responses.

The currently supported metaresponses are:

k_Forbidden
Raise this if the user doesn't have access to the requested resource.
k_PageNotFound
Raise this if the requested resource couldn't be found.
k_MethodNotAllowed
Raise this if resource doesn't support the requested HTTP method.
k_NotImplemented
This is roughly the HTTP equivalent to a "todo"

A meta response is associated with a component class name. For example, k_Forbidden resolves to k_DefaultForbiddenComponent. To get a customised handler for these types of responses, you can let your component creator return a custom component instead of the defaults.

Templates

Components usually return a html string. How they are rendered is largely left up to the developer. A common practise is to use a template engine though. Konstrukt includes a very simple template engine, which just wraps a regular PHP script in an output buffer. This strategy of using PHP as a template language works fine as long as you have some control over the provider of templates. It does have some drawbacks though, so some people might prefer to use a real template engine. Konstrukt comes with an example of how to use the Smarty template engine, but it should be equally simple to use any other template engine.

PHP-templates

To use the default template engine, you should instantiate and object of k_Template. The interface is simple; You pass a path to a PHP template. Calling render() will include the file inside a buffer and return the output. The calling component must pass a reference to itself to the template. This is to allow the template to access variables it might need. You should add methods on your component to provide the variables that your template might need.

The template binds a few global functions to make it easier for the template to call certain common features with a simple syntax. These are:

e()
This function escapes HTML special-characters in input and prints it in-place. Use this for embedding values in html-documents.
__(), t()
These are both aliases for $context->__(). You can use this hook for implementing i18n support in your application. Note that there is no default implementation for __(), so you need to explicitly implement this in your components, if you wish to support the feature.
url()
This is bound to $context->url().

Component creation

In the dispatch process, a component may delegate control to a sub component. In doing so, the new component must be instantiated first. This task is handled by a discrete object, called a component creator. This can be configured in the bootstrap, which allows you to replace this without having to mingle with the internals of the library.

DI containers

The intended use for a component creator, is to allow the use of a dependency injection container for creation of components. The base class for components (k_Component) doesn't have a constructor defined, which allows you free control over this for your components. This is practical because DI containers often use the constructor to provide dependencies. By default, Konstrukt doesn't provide a DI container, but it comes with bindings for Phemto, and it's very simple to write adapters for other containers.

createComponent

Most sub components are created from the dispatch process, but sometimes you need to create components manually. To do this, you can invoke the createComponent() method on a component, which would create a new sub component. The method takes an optional namespace, which is the namespace used for querystring parameters.

Encoding

Until version 6 becomes current, PHP is stuck with a primitive view of string data, where strings are treated as bytestreams. Many libraries, extensions and even core functionality in PHP, assumes that strings are single-byte streams. This means that each byte is interpreted as a character, the consequence being that only 256 different characters can be represented. Furthermore, the default charset assumed is ISO-8859-1 (also known as latin1). As long as we only want to represent western European texts this suffices, but in our multi cultural world, this is inadequate.

Using utf-8

Even if your main audience is English speaking, your users may still have foreign names, that can't be written with the limited charset of latin1. In addition, there are a number of ambiguities with regards to the latin1 standard, meaning that you can end up with corrupt data, even if you do things by the book. Currently, the best solution is therefore to use UTF-8 as encoding throughout your application. This strategy does have its pitfalls, but so does using latin1. It is important to get these things right from the beginning, since it's a thing that is very hard to change later.

Konstrukt distinguishes between the charset that it speaks on the HTTP level (The charset that the client sees) and the internal charset. By default, it will use UTF-8 in both places, but you can change the outside charset by a simple configuration option. Internally, you must use UTF-8. If you use a database, you should make sure that data is stored as UTF-8 or another Unicode capable encoding, and you should also make sure that the connection between PHP and database is set to UTF-8 (This only apply to some databases, such as MySql). Also, make sure that any files - especially template files - are saved as UTF-8 (Without BOM). This covers the most common problems with UTF-8.

There is a good overview of the core PHP functions, that needs special treatment to work with UTF-8 at http://www.phpwact.org/php/i18n/utf-8.

Interfacing with legacy applications (latin1)

If you're interfacing with code that speaks iso-8859-1, you will have to manually convert to utf-8. You can do this on by simply running the output from your renderers through the function utf8_encode. Additionally you will need to decode any input data (query(), body(), name() etc.) as these are internally represented as utf-8, regardless of the internal charset. If you follow these two guidelines, your code should fit nicely in to the framework. Of course, you are encouraged to upgrade to use UTF-8, since it will not only make things easier, but it will also eliminate a number of bugs and limitations.

Charset strategy

To change the charset strategy (The charset that the application presents itself in), assign a k_charset_CharsetStrategy in the bootstrap, using setCharsetStrategy(). Konstrukt comes with the following options:

k_charset_Utf8CharsetStrategy
The default choice. Encodes the response as UTF-8, and interprets the input as UTF-8.
k_charset_Latin1CharsetStrategy
Legacy compatibility. Encodes the response as ISO-8859-1, and interprets the input as ISO-8859-1.

It is strongly recommended that you keep the default (UTF-8) strategy.

Environment/setup

Konstrukt is fairly liberal about how files are organised. The library must of course be included in your application (Eg. lib/konstrukt.inc.php).

To make it easier to get started with Konstrukt, a "starterpack" is included, that gives you a default directory layout and configuration. If you're starting a new project, it's probably a good idea to follow this standard. However, these are just suggestions and it shouldn't be a problem to divert from it.

Currently, Konstrukt comes with two different variations of the starterpack. They are quite similar, where one is a subset of the other. starterpack_light doesn't have any external dependencies, except for Konstrukt. It doesn't feature a DI container and it uses the simple PHP-style templates that is provided through k_Template. The other option - starterpack_default adds Phemto as a DI container and the Smarty template engine. It also gives you a place to put test cases, using SimpleTest. This is the default recommended setup; If you don't want to use one of the components, you may find it easier to remove from the default package, rather than adding to the light package.

File layout

The file layout of the starterpacks are as follows:

config/               -- Global settings and other static configuration files
lib/                  -- Application specific PHP-code
lib/components/       -- Subclasses of k_Component.
log/                  -- Folder for various logfiles
log/development.log   -- The application debug log.
log/error.log         -- PHP error-log.
templates/            -- Template files
templates_c/          -- Compiled Smarty template files. This is specific for `starterpack_default`
test/                 -- Automated tests. This is specific for `starterpack_default`
test/unit/            -- Unit tests.
test/functional/      -- Functional tests (Eg. tests of individual components).
var/                  -- Place for various datafiles, such as sqlite database etc.
www/                  -- The directory that should be mounted as web root. Contains static content, such as Javascript files.
www/.htaccess         -- Contains configuration for Apache.

Static content

The www folder should be mounted as the DocumentRoot of your website. mod_rewrite is used to delegate control to Konstrukt. You can place static content in this folder, such as Javascript and CSS files or other static content. Apache will then serve these directly, without invoking PHP.

This setup assumes that www is mounted as the web root. If you want to run your application from a subfolder, you will have to specify the href_base to your bootstrap. In www/index.php, call setHrefBase() with the relative location to the web root.

Global handlers

Konstrukt comes with a default error handler and a class loader - k_exceptions_error_handler and k_autoload.

The error handler simply converts all errors into exceptions. It's recommended that you develop with this configuration, since it will force you to deal with errors, rather than ignoring them.

The class loader uses a simple convention to try and autoload undefined classes; Classnames are lowercased and underscores replaced with directory-separators. So a class named foo_Bar is expected to be defined in foo/bar.php. This convention is similar to that of PEAR and Zend Framework, except that file/directory names are all lowercased. The reason for this is that classnames are case insensitive in PHP, while filenames aren't (At least not on unix systems).

Naming convention

If you use the default autoloader (k_autoload), you should place your components in /lib/components/ and name them accordingly. Eg. The following component should be placed in the file /lib/components/foo/bar.php :

class components_foo_Bar extends k_Component {
  ...
}

Bootstrap

The bootstrap is an object that is used to create the root component and dispatch it. It's really just a factory, that makes it simpler to configure the application.

To start your application, create a default bootstrap using the k() function. This will return an instance of k_Bootstrap. The bootstrap has a number of default settings which you can override. Finally, the bootstrap can invoke the application, by calling the method run(). Each setter-method returns $this, allowing you to write in a fluent style.

The most important setters on the bootstrap are:

setComponentCreator
Sets the componentcreator to use.
setCharsetStrategy
Set the charsetstrategy.
setDebug
Enable/disable the in-browser debug-bar.
setLog
Specifies a filename to log debug information to.
setHrefBase
Sets the base href, if the application isn't mounted at the web root.

Debugging

Konstrukt comes with some tools for making development easier. Since the dispatch process of components isn't as simple as plain php or a front controller setup, it can be useful to see the exact chain of events, to figure out which component is responsible for rendering the output. To this end, the dispatch is logged. You can get debug output in two ways; Through the debug-bar or through the logfile. For a production site, you can disable debugging to improve performance.

You can enable/disable debugging with the relevant methods of the bootstrap.

In addition to dispatch logging, you can also send arbitrary information to the logger. Each component has a protected method debug() which will dump the argument to the logger/debug-bar. It works much like var_dump.

Logs

Dispatch and debug logging goes to the file /log/development.log. Additionally, the starterpack is configured to send php-errors to the file /log/error.log. While the development log is intended to use during development, the error log will usually be used on a production system. The log is configured by the .htaccess file in www. For a production site, you should edit this file to disable display of errors in the browser, and instead rely on the error log.

Functional testing

Konstrukt comes with a testing harnish for testing components. Since all access to the HTTP layer is encapsulated in adapters, it is possible to test your application down to the HTTP level without actually having a running web server. This is useful for writing automated tests. The testing harnish consists of an extension to the SimpleTest unit testing framework. The class k_VirtualSimpleBrowser acts as a drop-in replacement for SimpleBrowser. To use it in a testcase, write your WebTestCase as normal, but override the method createBrowser() as this:

class TestOfMyComponent extends WebTestCase {
  function createBrowser() {
    return new k_VirtualSimpleBrowser('components_MyComponent');
  }
  function test_request_root() {
    $this->assertTrue($this->get('/'));
    $this->assertResponse(200);
  }
}