Wednesday, May 5, 2010

Zoho Creator

So I found a company that provides basically the exact same functionality that I hope to provide with Wax. I knew there had to be someone out there with similar ideas, I just can't believe it took this long to find them. The company is called Zoho and their product is called Zoho Creator. It's basically designed to be an online database builder that lets you build custom applications around the database. So, if you want to see the long term aspirations for this project, check out http://www.zoho.com/creator/platform-features.html

Wax 0.11 and a Tutorial

So I finally managed to get a release together in time for this poster session. There are some things that I had hoped to have working that I just didn't have time for. The greatest contributor to this is that I did a rewrite on most of the blocks used by Wax after changing the routing methods.

Features Supported, but are probably still pretty buggy

  • Scaffolding (Create/Read/Update/Delete)
  • Dynamic Model (Modify/Add Attribute/Remove Attribute/Remove Model)
    • Fully implemented in DDS
    • Partially Implemented by WaxPDO (implements the DDM directly in SQL using ALTER TABLE)-- NOT RECOMMENDED
  • Context wrappers (similar to controllers, but not really), and Role Methods
  • Views
  • Layouts
  • Wax Querystring Routing (/Object/_id/method/arg/arg/...)

Things that kindof work, but aren't documented and are full of bugs

See the previous post for more details about these.
  • Login System (Requires creation of extra views and custom session management code)
  • ACL (Front-ends aren't done, Still very buggy)

Things that don't work / not implemented / TODO

  • Ajax support
  • Recursive Models (IE: auto-detect parents and children when fetching data)
  • Advanced Attributes (facebook-style)
  • Hidden Attributes (for the AntiSpam attribute, mostly)
  • Custom Forms (more on this once it's implemented)
  • Multiple layouts/output formats (ie: HTML, Ajax, RSS, etc.)
  • CouchDB interactivity with the Dynamic Model *high priority*
Documentation is still pretty rough, but any feedback is welcome. There's also quite a few security flaws that I haven't quite sorted out yet. You can check out the tutorial at The Getting Started wiki page and grab the downloads from The Google Code Page or from the sidebar on the right.

Monday, May 3, 2010

Users, Permissions, and the ACL

With frameworks inevitably comes the need to authenticate users and control permissions. In Wax, this need must be very carefully planned out, since the dynamic nature of the system allows for (almost) any object to have permissions on almost any other object. Let's consider a simple example: We have a Users object and a Tickets object. Regular users can view a list of tickets, while Administrators can CRUD the tickets. We want to make sure that these are the permissions applied in the system.

Creating a Model that has Permissions

As much as I would love to say that there is no coding involved in the creation of a login system, there are a few things that need to be done to make the system work properly.

Creating an Object with rLoginIdentifier and rPermissionHolder

The Wax DDM (Dynamic Data Model) provides two roles, rLoginIdentifier and rPermissionHolder which give regular old dumb objects the ability to act as smarter, permission having objects. First, an object must be created in the DDM. The object must contain a 'Username' field and a 'Password' field. Besides that you could store user information, last login information, etc., but 'Username' and 'Password' are all that are required. Secondly, the object must implement rLoginIdentifier and rPermissionHolder:
class Users extends DDM implements rLoginIdentifier, rPermissionHolder {}

That's pretty much it for the Login system

Implementing the rLoginIdentifier also gives the Users object the 'login' action, which actives the resource: /Users/login - which is the front-end to the login system. The Login system allows you to turn a regular dumb object into something useful with only 1 line of code (the Users class definition). Normally, the DDM handles all actions directed at a dynamic model, but in this case, we've overridden the basic DDM and given the Users object all of the dynamic functionality but added some additional functions as well.

Using the ACL

Using the ACL is just as simple as setting up a login system. In fact, half of setting up the login system is actually setting up the ACL. The rPermissionHolder role exposes 3 methods which interface with the Dynamic Data Model which allow for Getting/Setting permissions on resources.

Getting a User's Permissions

The User information is stored in the PHP $_SESSION object, which allows you to access the actual user information very easily ($_SESSION['User']). Using this information, an actual model can be instantiated:
$user = new Users($_SESSION['User']);
The permissions of any resource can then be checked with IsAllowed or GetPermissions.
if ($user->IsAllowed("SomeModel/modify")) {    
    // success
}
else {    
    // InvalidPermissionsException
}
$permissions = $user->GetPermissions();
/**
* Permissions would be something like:
* Array(
*    [SomeModel/] => 1,        // User has access to all function of SomeModel
*    [SomeModel/delete] => 0   // But there is also an explicit DENY to SomeModel/delete
* )
*/
By default, all permissions are denied for all users. Each ACL entry represents an ALLOW permission for some resource. As shown above, explicit DENYs can also exist, which is useful when you want to grant all permissions EXCEPT for some action-- in the above case, Deleting the objects is not allowed.

Sunday, May 2, 2010

Login- A good example of customizing the dynamic model

With the Dynamic Data Model rewritten in the new routing format, it was relatively easy to get the Login roles working. The next step is to make the ACL work. The login system is implemented in 3 different pieces:
  • The Users object
  • The rLoginIdentifier roles
  • The UsersLoginCtx context
Each of these pieces serves a different purpose, explained below.

The Users Object

The Users object contains the basic object that extends DDM. Additionally, it implements the rLoginIdentifier which provides the Authenticate() and session management methods. This object also provides the target for the actual request-- as in the URL for accessing the login function is:
/Users/login

rLoginIdentifier

The rLoginIdentifier role provides methods that Authenticate the user against the dynamic model. It makes use of the PasswordAttribute class and the rPasswordHasher role to hash the password using a User-specified hash function. The LoginIdentifier role also provides access to 2 session management methods:
  • SetSession($var, $value)
  • DestroySession()
Where SetSession can set and unset session variables, while DestroySession can destroy a session for logout purposes.

UsersLoginCtx

This is the class that actually handles the Login request. Requests are handled either by a corresponding context name (ie: UsersLoginCtx) or role method (Users->Login). In this case, the context is used since each application's Login method will be different and as such, should not be coded as a role method. Since the Authenticate role only returns the result of the actual Authentication, this context is responsible for handling the result of the Authenticate function. It takes the result and stores it in the session, then redirects the User to the home page. This context must be coded specifically for each application. It allows for the basic Authentication module to be very dynamic (providing a list of different hash functions), while allowing the actual session management to be completely custom.

More To Come...

This is just this first example of the model of programming that Wax and the IWH package are built on. The roles will provide commonly used functionality (scaffolding, the dynamic data model, login/sessions, etc.), while the contexts provide a way to set up these function calls around custom application functionality.

Sunday, April 25, 2010

MVC Got in the Way, So I Got Rid of It

As development of this framework went on, I began to realize that I didn't need to use MVC anymore. In fact, I realized that the bulk of the work for the IWH project was simply working around MVC in order to get the system I wanted. One of these major challenges was adding special functionality while still maintaining the dynamic data model ideas.

Role methods to the rescue

Instead of analyzing a request to determine which controller should handle the request, the request provides a precise target of which code to run. For example, in MVC, this request would run the view method in the PostsController and fetch record #3:
/Posts/view/3
Instead of trying to figure out how Controllers fit into this new model, the routing method was rewritten, so the same request above would be rewritten as follows:
/Post/3/view
Which is analyzed into "I want to perform an action on a Post object. The object's id is 3, and i want to run the view method". Instead of routing this through a controller, we can instead give the Post object the ability to play the role of a ViewActionHandler:
class Post extends WaxObject implements rViewActionHandler
Which would link the Post object to the ViewActionHandler. Similarly, this concept can be applied to static pages as well:
/Home/mobile[/index]
Would tell Wax that the user wants to view the index() method on the Home object. This Home object's ID happens to be 'mobile'. We can use this identifier to link in different stylesheets, datasets, and anything else to distinguish the mobile view from the regular one.All in all, what does this mean? Well basically, it means that the word 'Controller' won't be found anywhere in the Wax source code because there aren't any controllers.

Wednesday, April 21, 2010

InsertWebsiteHere Progress

So it's been awhile since posting anything, and the main reason for this is that it's hard to explain some of the things going on in this system. However, now that I've got (most of) the hard parts done, I can give an overview of what's been put into this system and what's required to make it work.

The IWH DataSource Interface

First of all, the most important part of the IWH project is the IWH DataSource interface. The interface provides a list of standard functions that are used by IWH to modify its dynamic model. The default IWH DataSource (IWHDS) at this time wraps around PHP's PDO class. The methods contained in IWHDS perform the necessary translation (in this case, SQL queries) for altering and accessing the dynamic model. Below is a brief explanation of each table in the default schema:
  • models: stores a list of different models that are stored by the database. This is a simple id => name assocation, with an extra field for a description.
  • model_structure: stores a list of attributes for the stored models. This table is really the heart of the dynamic model system, as it defines attributes, types, default values, and order. Records in this table are linked to their respective model via model_id.
  • structure_options: one feature in IWH that hasn't been present in any other dynamic systems I've created is the ability for attribute types to have custom options. For example, a timestamp field would be able to store an option specifying what format to use. These options are specific to their respective structure, so 2 timestamp fields would be able to use 2 different formats, depending on how they were set up.
  • records: a list of records stored by the system. This table is primarily responsible for maintaining a list of all records, and stores only the type of model that the reference refers to.
  • record_data: this table stores all of the information for the data models. It is easily the largest table in the system (in terms of number of records). Information is always stored as a TEXT type, as PHP provides the necessary facilities for converting to the proper type automatically. A TEXT type ensures that (almost) all types of data can be stored here. Fields in this table are tied to their parent record (record_id) and the type of attribute (structure_id). The attribute type determines how the stored data is presented to the user.
Combined with this database structure, a special programming interface needed to be developed in order to really leverage the dynamic nature of the system. The interface was designed to handle basic scaffolding automatically, with the ability for the programmer to override any defaults.

Super-Scaffolding and Attributes

In a traditional MVC system, scaffolding is commonly used to get a base system up and running. The scaffolding provides a form for input as well as the views necessary to present the data. Scaffolding in Wax/IWH is a much different process. Since the models may constantly be changing, the scaffolding is done automatically, but with a twist-- instead of writing custom views for each different MODEL, you write custom views for each different TYPE OF ATTRIBUTE. This greatly reduces the amount of code necessary to provide a working system, and allows a much higher level of code reuseability. Attribute types are stored in the attributes.wax block (within iwh.wax), and each one is made up of 4 basic parts (a context and 3 views):
  • AttrnameAttrCtx: Each attribute has a corresponding context for doing any custom manipulation of data before sending the data to the user or the database. In the simplest sense, it acts as a controller. It contains these methods:
    • view(): Pass the data on to the view that will display the information. Any custom formatting (timestamp formats, for example), can be done here.
    • edit(): Pass the data on to the view that will present an input form to the user. This method is used both for adding and editing of data, so it should be coded accordingly. This method is usually pretty simple, as it must present data in a way that can be shown by standard HTML controls.
    • editor(): All attributes have the ability to store custom options. The example I've been referencing is if timestamps wanted to store a format. In that case, the editor() method might return a list of common formats used for displaying times, of which 1 could be chosen as the display format for this attribute.
  • Each method in the AttrCtx has a corresponding view file which is embedded into the necessary forms via the AttrRenderCtx

And soon to come...

Users and ACL

So what's next? Obviously, a system like this isn't of very much use if anyone can edit the data or the data model, so one of the primary goals right now is the development of an integrated ACL and user system. This change will likely add another table or two to the schema, since ACL and User Control isn't the type of information that can be stored dynamically. The dynamic nature of the system will still be preserved, however, since dynamic models would be able to be linked to User accounts, allowing for the creation of profiles, favorites, etc.

RSS/ATOM/XML/and other Web 2.0 stuff

Additionally, getting data out of the system is just as important (maybe more important) than putting it there in the first place. As a result RSS/ATOM feeds will become an important part of future versions of this system. Using the ACL in conjunction with the dynamic models, the included RSS/ATOM feeds will allow for REST APIs to automatically be created for these data models.

Upcoming Poster Session

I hope to have most of these new features done by May 7th in time for the poster session. At this session, I plan to show off the features by upgrading (and in the process, rewriting) a helpdesk system for use by the Rensselaer Union System Administrators. If everything goes according to plan, it should be a pretty exciting demonstration.

Friday, February 19, 2010

CoreDCI split into separate project

Wax's underlying DCI core has now been split into a separate library, called CoreDCI, and has been packaged as a way to provide DCI functionality in a more generic scope. Version 1.0 of CoreDCI was released today, and provides:
  • DCIObject - allows for the creation of role-playing objects
  • Context - a context class that is specifically designed for facilitating the execution of role methods
  • DCIException - a custom exception class that provides a stacktrace that more accurately shows the DCI call stack
  • The Account Example: a test file showing how to define roles, contexts, and model objects, then use the role methods to perform a Money Transfer operation. Also demonstrates the functionality of the DCIException.
The library is available for download at The CoreDCI project page.