Archive for the ‘Garden’ Category

CSS 101

Wednesday, February 11th, 2009

A bit of help, if you please…

Check out this page, which contains a 200px wide div floated left, and a fieldset. Note how the fieldset is completely contained to the right of the div.

Now check out this page, which also contains a 200px wide div floated left, but instead of a fieldset, next it has a div. Note how the div goes behind the floated element all the way to the left side of the screen.

I was under the impression that (at least in Firefox) all elements are created equal, and that the fieldset in the first example must just have some styles applied (by the browser) to make it stay completely to the right of the floated div. I was hoping that I could somehow force the div in my second example to behave like the fieldset in the first example, but I can’t seem to figure out how to make that happen without forcing specific margins on the div.

Any ideas?

Garden Preview Part XIV: Errors & Debugging

Tuesday, February 10th, 2009

Garden Preview Part I: Overview
Garden Preview Part II: Filesystem
Garden Preview Part III: Anatomy of a Request
Garden Preview Part IV: Views
Garden Preview Part V: Data
Garden Preview Part VI: Models & Forms
Garden Preview Part VII: Ajax
Garden Preview Part VIII: Plugins
Garden Preview Part IX: Roles & Permissions
Garden Preview Part X: User Registration
Garden Preview Part XI: Structure
Garden Preview Part XII: Internationalization & Localization
Garden Preview Parth XIII: Syndication

A number of months ago I posted a preview of Garden’s error page. Since that time, both the application, and the error screen have become something much more. Debugging has been crucial in the development of Garden over the last two months, and the error screen is the main source of help in that process.

The Setup

All of Garden’s custom error handling is accomplished with PHP’s set_error_handler function, which allows you to call your own function whenever an error occurs. There are a few shortcomings where your custom function will not get called. To quote the PHP manual:

The following error types cannot be handled with a user defined function: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, and most of E_STRICT raised in the file where set_error_handler() is called.

If errors occur before the script is executed (e.g. on file uploads) the custom error handler cannot be called since it is not registered at that time.

Luckily, 99% of these “unhandled” errors are extremely easy to debug. Since Garden does most of it’s complex processing before the page is rendered, these unhandled errors will typically look like this:

PHP Error

This example is a parser error, and obviously occurred on line 19 of that particular file because a class that was being instantiated had not yet been declared. An easy fix.

But, as you can imagine, errors can be much more difficult to debug than that, and so enters Garden’s error page:

Garden Error

This error page is completely contained within the error.master view. If for some reason Garden fails to find the error master view, it’s error function has a simpler version of this page explaining the error.

What you get

Fatal Error in PHP.ErrorHandler(); tells you what object & method threw the error. In this example, it was a PHP error (ie. totally unexpected by the application). If it is a custom Garden error, you might see something along the lines of: Fatal error in ProfileController.BuildSideMenu();.

Next you get the actual error message. In this case: Undefined property: ProfileController::$DoesntExist

Everything after the error message provides information about that error message, starting with:

Where the error occurred: This example first tells you in what file the error occurred, followed by an excerpt from the file with the actual error line highlighted.

Backtrace: Next you get a backtrace of what files & functions/methods were called which led to the error. The backtrace can be invaluable in figuring out what actually led to the error being thrown.

Queries: Next you have a summary of all database queries that were run before the error was encountered.

Variables in local scope: Finally, if there are any variables in local scope at the time of the error, their names & values will be written out. In this example, there are no variables in local scope, so there are none written.

Additional Information: If dealing with a remote bug, it is always incredibly helpful to get additional information about the system on which the application is running. So, the additional information section contains information about:

  • What version of Garden is running.
  • What version of PHP is running.
  • What operating system the server is running.
  • What referrer led to the page where the error was thrown.
  • What user-agent was being used when the error was encountered.
  • The request route that led to the error.

Using the Error Page

I found that there was a small bit of a learning curve with using this error page. I was just used to having to deduce what the problem might be and following my gut instinct as I did with most of Vanilla 1. However, after a few days with all of this information available, I found that bugs were getting resolved faster than ever before. Now I am at the point where a quick glance at the error page can tell me exactly what the problem is so I can be moving ahead in a matter of moments. I know that it will be invaluable to both application and plugin developers.

Post Launch Errors

Of course, we don’t want end users to have to deal with an error screen like this. With that in mind, Garden has a “Debug Mode” switch that, unless turned on, tells Garden to use a *different* master view for errors. The other master view, which can be customized further using themes, simply states that an error was encountered and that the user should report the problem to an administrator. Error mode will be turned off by default in the release version of Garden.

Garden Preview Part XIII: Syndication

Monday, February 2nd, 2009

Garden Preview Part I: Overview
Garden Preview Part II: Filesystem
Garden Preview Part III: Anatomy of a Request
Garden Preview Part IV: Views
Garden Preview Part V: Data
Garden Preview Part VI: Models & Forms
Garden Preview Part VII: Ajax
Garden Preview Part VIII: Plugins
Garden Preview Part IX: Roles & Permissions
Garden Preview Part X: User Registration
Garden Preview Part XI: Structure
Garden Preview Part XII: Internationalization & Localization

With Garden, turning any view into a syndication view is a breeze.

Creating a Feed

Creating a syndication feed is just as easy as creating a normal web page. For example, let’s say I wanted to create a feed for all of the discussions in Vanilla. I could add a “feed” method to my DiscussionsController class in Vanilla. Within that method I would change the master view to whatever syndication format I want to use (Garden provides RSS2 and Atom master views by default), I’d load the appropriate data using my Discussion Model, and then I’d create a view for my feed method which looped the records, writing out each item.

That’s pretty easy, but it seems silly to create a custom method for loading data that already has a method created to do the same thing. For example, the DiscussionsController I just mentioned already has an “Index” method that loads all of the latest discussions and displays them as xhtml. All I really need to do is create a custom view for the rendering of the feed items and use the data loaded by that method. Garden let’s you do that easily with…

Automatic Feed Urls

You can turn any url in Garden into a syndication url by prefixing the route with “rss” or “atom”. Garden will then know to (a) select the appropriate master view for that syndication type, and (b) select an alternate rss or atom version of the view file. So, if I were to change the url to Vanilla’s discussions on my local dev server:

http://localhost/garden/discussions

to

http://localhost/garden/rss/discussions

Garden would select the rss master view, and instead of selecting the default view (index.php), it would look for an index_rss.php view in the same view folder.

So, all I would have to do in order to turn any page in Garden into a syndicated page, is to create an alternate view for the data with the appropriate syndication method as a view filename suffix (ie. viewfilename_atom.php or viewfilename_rss.php).

Client Feed Caching

What if the feed you are serving changes rarely? It doesn’t make sense to waste unnecessary bandwidth and CPU cycles on delivering data that hasn’t changed. Garden takes care of this with HTTP’s conditional GET mechanism. The controller base class has a SetLastModified($Date) method that allows you to specify the last date that this particular feed (or page, for that matter) was modified. Clients will then send this information back to Garden when they are requesting data, and Garden will know to either (a) deliver the new data, or (b) tell the client that there have been no changes and send nothing back.

Garden Preview Part XII: Internationalization & Localization

Tuesday, January 27th, 2009

Garden Preview Part I: Overview
Garden Preview Part II: Filesystem
Garden Preview Part III: Anatomy of a Request
Garden Preview Part IV: Views
Garden Preview Part V: Data
Garden Preview Part VI: Models & Forms
Garden Preview Part VII: Ajax
Garden Preview Part VIII: Plugins
Garden Preview Part IX: Roles & Permissions
Garden Preview Part X: User Registration
Garden Preview Part XI: Structure

Literally entering the codebase *after* the release of the alpha version of Vanilla 1, internationalization and localization in Vanilla have always been an afterthought. I’d like to say that the advances in localization in Garden are great, but the truth is that they aren’t much better than Vanilla 1 if for no other reason than the fact that PHP itself has not gotten much better at it since PHP 4. While PHP 6 promises to have some great advances in it’s support for internationalization and sundry issues that go along with it, PHP 5 has a truckload of problems in this regard.

Cutting our losses

Vanilla (and Garden) are all about install-and-go. This means that I’ve always felt that you should be able to upload Vanilla to your server, and as long as you have PHP and MySQL installed, you’re good to go. Garden goes one step beyond that in saying that you need PHP 5 and MySQL 5 in order to run the code. Considering that a large proportion of the people who download from Lussumo don’t even run their own servers (or have control over the PHP extensions that are installed), I’ve cut my losses with regards to localization and internationalization so that people don’t need to have special PHP extensions installed if they want to run Garden in a language *other* than English.

The Old

So here is what hasn’t changed since Vanilla 1: Language definitions are still saved in an associative array of Term -> Definition pairs.

The New

Translation Codes VS Plain English
In Vanilla 1, I used translation codes (ie. “ClickHereToLogin” instead of “click here to log in”) throughout the application. The translations for these codes were then contained in the definition file. For better or worse, with a few minor exceptions, this time around I decided to just put the plain English right into the application. I’ve found that it makes the readability of the application much easier as you are coding it. Plus, it means that the English version of the translation file can basically remain empty since the default definitions are right in the core application.

Convenience Method
I’ve created a Translate($Definition) {} function that can be used anywhere in the application. So, you no longer have to type out any long convoluted call to a translation method through various objects. What you’ll often see in the application is code like:

<h1><? echo Translate('This is a Heading!'); ?></h1>

sprintf Replacements
Rather than using the //1 //2 notation like I did in Vanilla 1, I’ve opted to use PHP’s native sprintf() for all string replacements in translations. This means that you’ll often see the %s$1 notation used by sprintf sprinkled throughout language definitions. I’m hoping it will provide some clarity as well as usefulness for where to place various words within the strings as new languages are added.

Multiple Definition Sources
While Vanilla 1 kept all language definitions in a single file, Garden has a number of different files that contain definitions. When a language is selected, Garden will crawl it’s own filesystem to find locale files of the selected type. Garden then takes all of the definition files that it found and includes them in the cache/locale_mappings.php file. So, for example, if you change from en-US to fr-FR, Garden will crawl through all of the plugins and applications looking for /locale/fr-FR/definitions.php files, then replace the current mappings in cache/locale_mappings.php with the new ones it found for the fr-FR locale.

The Borrowed

Obviously there are some hurdles to overcome with language translations, and I am going to be relying heavily on the Lussumo Community in order to make this part of Garden shine. As plugins and applications go through code-review, their language definitions will be entered into a core language definition database. Every time a new version of a plugin or application is released, it will once again have to go through code-review, and it will be re-analyzed for new language definitions (and removal of old ones). Once the translations have been entered into the database, they will then be in the charge of language translators.

Any member of the Lussumo community will have the ability to nominate themselves as a language translator for specific locale(s). As new definitions are added to the database, they will then appear to translators for any/all available languages. As the translators create the definitions, the plugin and application authors will have those translations become available to them to either (a) add into their plugins/applications, or (b) simply be available to end-users as an ancillary download with the plugin or application (we’ll have to see what works best).

The Blue

Someday down the road PHP 6 will become easier to adopt, and (among other things) we’ll have proper date and number formatting available. Until then, I haven’t solved all of the problems associated with internationalization, but I think we’ve made some fairly large advancements. At the very least we should get to the point where we are releasing the core application with more than one language available (ie. the end-user gets to select what language they want as they install the product for the first time). Most of all I am eager to get the community highly involved in the translation process. I know that there are *many* users who speak numerous languages, and I realize how important it is to leverage that resource.

Garden Preview Part XI: Structure

Tuesday, January 20th, 2009

Garden Preview Part I: Overview
Garden Preview Part II: Filesystem
Garden Preview Part III: Anatomy of a Request
Garden Preview Part IV: Views
Garden Preview Part V: Data
Garden Preview Part VI: Models & Forms
Garden Preview Part VII: Ajax
Garden Preview Part VIII: Plugins
Garden Preview Part IX: Roles & Permissions
Garden Preview Part X: User Registration
Garden Preview Part XI: Structure

Most open-source web applications have database setup scripts that are simply a set of SQL instructions that you can inject directly into your database (typically mysql) to get going. Vanilla 1 was no exception to this rule. The benefit of this approach is that you can quickly and easily get your app up and running. The downside to this approach is that when it is time to upgrade the application to a newer version, you have to write extremely convoluted scripts to figure out what application version the user currently user has, or write scripts to examine database table structure to see what fields need to be removed, or what fields need to be added. Hell, it’s even difficult to understand what I just wrote, let alone the code that would go along with it.

The Database Structure Class

Garden does not have any SQL install or update scripts. Instead, every application in garden has a structure.php file which can be used by either the Garden installer, or by the application management screen when enabling that application. The structure.php file contains a set of instructions on how to build the structure of the database. This file uses the DatabaseStructure class to define the structure of the database.

The class itself is extremely simple to use. Like the database class, the DatabaseStructure class uses method chaining, and it contains methods to create/drop/rename tables, create/drop/rename table columns, and create/modify views.

Tables & Columns

Each application’s structure.php file resides in that application’s “settings” folder (the same folder that contains the appliation’s about.php file). So, the structure file for Garden resides in /path/to/root/applications/garden/settings/structure.php. Let’s take a look at an example of how I create the user table in Garden:

// User Table
$Construct->Table('User')
   ->Column('UserID', 'int', 10, FALSE, NULL, 'primary', TRUE)
   ->Column('PhotoID', 'int', 8, TRUE, NULL, 'key')
   ->Column('Name', 'varchar', 20, FALSE, NULL, 'key')
   ->Column('Password', 'varchar', 32)
   ->Column('About', 'text', '', TRUE)
   ->Column('Email', 'varchar', 200)
   ->Column('ShowEmail', array('1', '0'), '', FALSE, '0')
   ->Column('Gender', array('m', 'f'), '', FALSE, 'm')
   ->Column('CountVisits', 'int', 8, FALSE, '0')
   ->Column('CountInvitations', 'int', 2, FALSE, '0')
   ->Column('InviteUserID', 'int', 10, TRUE)
   ->Column('DiscoveryText', 'text', '', TRUE)
   ->Column('Preferences', 'text', '', TRUE)
   ->Column('Permissions', 'text', '', TRUE)
   ->Column('Attributes', 'text', '', TRUE)
   ->Column('DateSetInvitations', 'datetime', '', TRUE)
   ->Column('DateOfBirth', 'datetime', '', TRUE)
   ->Column('DateFirstVisit', 'datetime', '', TRUE)
   ->Column('DateLastActive', 'datetime', '', TRUE)
   ->Column('DateInserted', 'datetime')
   ->Column('DateUpdated', 'datetime', '', TRUE)
   ->Column('HourOffset', 'int', 2, FALSE, '0')
   ->Set(TRUE, FALSE);

The hardest part of understanding this SQL is knowing what each of the arguments in the “Column” method are. I’ve done my best to keep these arguments similar to the way they appear when writing a column definition in SQL. Let’s take a look at all of the arguments:

public function Column(
    $Name, 
    $Type, 
    $Length = '', 
    $Null = FALSE, 
    $Default = NULL, 
    $KeyType = FALSE, 
    $AutoIncrement = FALSE
) { }

Name (string):
The name of the column to create.

Type (mixed):
The data type of the column to be created. If an array of values is provided, the type will be set as “enum” and the array will be assigned as the column’s Enum property.

Length (mixed, not required, default “empty”):
The length of the column.

Null (bool, not required, default FALSE):
Does the column allow null values.

Default (mixed, not required, default NULL):
The default value of the column. If NULL is provided (default), there will be no default value.

KeyType (string, not required, default FALSE):
What type of key is this column on the table. Options are primary, key, and FALSE (not a key).

AutoIncrement (bool, not required, default FALSE):
A boolean value indicating if this column auto-increments.

Once you master the arguments for the column method, building and altering tables is a breeze.

The Set() method (used above to execute the creation of the user table) also has some important arguments:

public function Set(
    $Explicit = FALSE, 
    $Drop = FALSE
) {}

The Set method creates the table and columns specified with $this->Table() and $this->Column(). If no table or columns have been specified, this method will throw a fatal error.

Explicit (bool, not required, default FALSE):
If TRUE, and the table specified with $this->Table() already exists, this method will remove any columns from the table that were not defined with $this->Column().

Drop (bool, not required, default FALSE):
If TRUE, and the table specified with $this->Table() already exists, this method will drop the table before attempting to re-create it.

As you can imagine, these are some pretty powerful commands that you must pay close attention to. In 90% of my structure scripts, Explicit is TRUE, and Drop is FALSE. Despite this fact, I have kept both arguments FALSE by default so that tables are not dropped and columns are not removed if a user does not know what they are doing.

As I mentioned, there are other methods available to you if you don’t want to redefine an entire table, but you do want to add or remove columns (or drop entire tables). Those are: Drop (allows you to drop a table), RenameTable, DropColumn, and RenameColumn.

Views

Using the database class, you can also quickly and easily build a query and turn it into a view. Here is an example of building a view:

$View = $Database->Select('rp.*')
   ->Select('p.Name', '', 'Permission')
   ->From('RolePermission rp')
   ->Join('Permission p', 'rp.PermissionID = p.PermissionID')
   ->GetSelect();
$Construct->View('vw_RolePermission', $View);

Benefits

Why did I bother building this class? I originally got the idea because I found that I was keeping a SQL script that I would constantly make changes to, and re-run on the database, essentially wiping out my test data every time. It got me thinking about how upgrades are difficult because of database structure changes. I ended up writing this class in a very short amount of time, and then spending a lot of time turning my rather large SQL script into a structure.php file. I was delighted to discover that changes made to my structure.php file would quickly and easily apply to the database with a quick run of the file. So, I could easily add a column to a table definition, run my structure script, and go back to happily using the application, and making use of my new column, while all of my testing data remained intact.

This means that when you release new versions of your applications, all you need to do is update your structure file (which you will likely be doing as you add features and fix bugs), and all database structure changes apply when the application is re-enabled by the user.

This class can also be used by plugins to quickly and easily add (or remove) columns from tables (or even create tables). The sky is the limit.

This class has gone far beyond my initial hopes. At this point I don’t anticipate ever writing an upgrade script for any application in Garden. Everything should be handled by the application management screen, or the initial install script that comes prepackaged with Garden.

Garden Preview Part X: User Registration

Monday, January 12th, 2009

Garden Preview Part I: Overview
Garden Preview Part II: Filesystem
Garden Preview Part III: Anatomy of a Request
Garden Preview Part IV: Views
Garden Preview Part V: Data
Garden Preview Part VI: Models & Forms
Garden Preview Part VII: Ajax
Garden Preview Part VIII: Plugins
Garden Preview Part IX: Roles & Permissions
Garden Preview Part X: User Registration
Garden Preview Part XI: Structure

Depending on the type of website you are building, your user registration needs could vary greatly. You might have a private, friends-only Vanilla installation. You might have a corporate, local-network installation that requires a no-frills setup. You might be a very public site where you need a bot-checker or even human-checking of applicants. Garden covers all of these methods and more. There are five methods for registration that are included in Garden out of the box.

Closed

Simply put, registration is closed. Going to Garden’s registration screen tells you just that. Administrators can then add users manually (and send out welcome emails as they are created) using the user administration screens.

Basic Registration

Basic Registration

No frills user registration. Users are prompted to enter their username, email, password, and are granted access immediately after submitting the form.

Captcha

Captcha Registration

Using the free recaptcha.net service, this option allows you to add a captcha anti-bot tool to prove that the person applying is, in fact, a person. Assuming that the user sufficiently proves this, they will be granted access immediately after submitting the form.

Approval

Administrative Approval Registration

Administrative approval is my personally preferred method for granting users access to your site. With this method, after registration, users are added to an “Applicants” list that administrators can then review and choose to approve or deny access. A little slower than most registration methods, but far less prone to allowing bad seeds into your user base.

Invitation

Invitation Registration

Users are granted a pre-defined number of invitations-per-month which they can send out to friends and colleagues. The only way new members can get into the system is by receiving one of these invitations. The system keeps track of who invited who (and I can only imagine the fun that someone might have creating a plugin to map out the family tree of a user base created in this way).

Session Handshakes

With Vanilla 1 I tried to adopt a newfangled method of integrating user tables between applications so that, for example, a wordpress installation could use vanilla’s user table or vice versa. In the end, this method was neat, but difficult to implement. Not to mention that it required that the user tables from both applications be in the same data source. What if the other app’s db was in postgre? What if it you wanted to use some other type of authentication altogether that had nothing to do with databases?

In Garden I’ve taken a much simpler approach to user registration/integration. In order to integrate Garden’s user table with any other application, all you would need to do is write a session handshake function, and create a plugin to fire before Garden’s session starts. In the session handshake function, you can validate that the request is from a trusted source using whatever method you desire, and then give it a username to create. The user will be created if it doesn’t exist, or the user will be authenticated otherwise. By the time Garden gets to loading it’s own session, the user has already been authenticated (and possibly even created if it hadn’t exited in the Garden database before) and signed in. The user should seamlessly be coasting through Garden pages without even knowing they were registered.

Garden Preview Part IX: Roles & Permissions

Monday, January 5th, 2009

Garden Preview Part I: Overview
Garden Preview Part II: Filesystem
Garden Preview Part III: Anatomy of a Request
Garden Preview Part IV: Views
Garden Preview Part V: Data
Garden Preview Part VI: Models & Forms
Garden Preview Part VII: Ajax
Garden Preview Part VIII: Plugins
Garden Preview Part IX: Roles & Permissions
Garden Preview Part X: User Registration
Garden Preview Part XI: Structure

A lot of different people approached me with a lot of different ideas for roles & permissions in Garden. I found that the most common requests were for (a) a cleaner UI, and (b) the ability to assign a single user to multiple roles. As with all things in Garden, I spent a lot of time doing research into permission methodologies adopted by other frameworks and applications. I found that there are a lot of different methods out there. And while I agree that Vanilla 1′s permissions were not powerful enough, most of the other options being adopted were simply too much for what I am trying to accomplish. Either they would take too many runs to the database for individual permissions, or they simply became too much work over time as new ones were added.

In the end I met the following goals:

1. Permissions are easy to organize.
Permission names are written with a “dot” delimiter, and must contain at least three portions. The first portion represents the application or plugin that the permission is for. The second portion represents the element for which you are defining permission, and the third (and often final) portion represents the action being allowed (you might consider it to be a “verb”). So, a list of permissions might appear as:

Garden.Settings.Manage
Garden.Applications.Manage
Garden.Plugins.Manage
Garden.Themes.Manage

As mentioned, there can be more than three portions to the permission definition. If there are more than three, the first and last portions still represent the application/plugin and the verb respectively. The middle portions then represent a finer grain view of the element for which the permission is being defined. A good example of this would be categories in Vanilla. For example: if there were two categories in your Vanilla installation (General and Testing), their permissions would appear like so:

Vanilla.General.Discussions.Add
Vanilla.General.Discussions.Edit
Vanilla.General.Discussions.Announce
Vanilla.General.Discussions.Sink
Vanilla.General.Discussions.Close
Vanilla.General.Discussions.Delete
Vanilla.General.Comments.Add
Vanilla.General.Comments.Edit
Vanilla.General.Comments.Delete
Vanilla.Testing.Discussions.Add
Vanilla.Testing.Discussions.Edit
Vanilla.Testing.Discussions.Announce
Vanilla.Testing.Discussions.Sink
Vanilla.Testing.Discussions.Close
Vanilla.Testing.Discussions.Delete
Vanilla.Testing.Comments.Add
Vanilla.Testing.Comments.Edit
Vanilla.Testing.Comments.Delete

Permissions are stored in the Permission table, and relate to roles via the RolePermission table. Organizing the permission names in this way allowed me to take further steps to arranging them in a much more user-friendly way on the edit role screen:

permissions

As you can see, it’s a lot easier to read than the old “giant list of permissions” that you’ve worked with in Vanilla 1. There are even some cool usability tricks I’ve done with jQuery to make it really easy to check rows, columns, or entire grids with single clicks.

2. Permissions are easy to add.
Adding permissions is easy whether they’re for plugins or applications. You might remember the plugin definition from last week’s preview. The beginning of the plugin file contained an associative array of information about the plugin. One of the values available to plugin authors was “RegisterPermissions”. This value can be defined as an array of permission names. Any values in this field will be added to the permission table when the plugin is enabled (unless they are already present, in which case they will be ignored). If you are creating an application, there is a similar RegisterPermissions value available in the /settings/about.php file which performs the exact same thing.

3. Permissions are smart.
Because the first portion of the permission name relates to the application or plugin that defined it, the role screen knows to ignore permissions that are related to applications and/or plugins that are not enabled. This means that if you disable a plugin or application, those permissions will no longer clutter up the “Edit Role” screen unnecessarily. Furthermore, if you then re-enable that application and/or plugin, the old role permissions you had for it will re-appear – so you don’t have to redefine them every time.

4. Users can have many roles.
Definitely the most requested feature related to permissions was the ability to have a single user relate to many roles. In Garden, this is achieved with a white-list methodology. This means that the default permissions for any user is to “deny all”. Every permission that a user gets allows them access to that element. So, if a user is assigned to one role that has permission to post discussions, and another that does NOT have permission to post discussions, the allow permission will overrule the deny permission, and they will be able to post discussions. Think of it in terms of a “Banned” role (where the role has no permission to do anything), and an “Administrator” role (where the role has permission to do everything). If a user were assigned to both Banned and Administrator, the Administrator role’s permissions would overpower the banned role and the user would have access to everything.

For me, personally, this is going to make my life much easier as the Lussumo community site grows and I can easily grant more and more users access to roles like: “Language Translator”, “Plugin Administrator”, “Documentation Administrator”, “Forum Administrator”, etc – without having to create custom roles for each unique combination thereof.

5. Permissions are still fast.
Probably my favourite thing about permissions in Vanilla 1 was how they were stored in the user table as a serialize array. Doing this allowed me to pull all user session and permission information out with a single query. This meant that every time a permission was to be checked, the application would not have to take a trip to the database. Furthermore, it was a lot faster than running one query to get user session information, and another query to pull all permission rows (like a lot of other applications do). When you consider that there can be an unlimited amount of permission checks on a single page load, a complex permission methodology can really slow an application down.

Luckily, we don’t have to worry about any of that nonsense with Garden. Permissions are still cached in a field on the user table, and are still pulled out with the session information in a single, fast query.

Next
I sincerely hope that next week I’ll be able to start showing some screenshots. Development was slow through December as I had to overcome some significant hurdles with Vanilla. We’ll see if I get time to spend doing design this week. If not, I’ll probably talk about plugin and application management.

Garden Preview Part VIII: Plugins

Monday, December 29th, 2008

Garden Preview Part I: Overview
Garden Preview Part II: Filesystem
Garden Preview Part III: Anatomy of a Request
Garden Preview Part IV: Views
Garden Preview Part V: Data
Garden Preview Part VI: Models & Forms
Garden Preview Part VII: Ajax
Garden Preview Part VIII: Plugins
Garden Preview Part IX: Roles & Permissions
Garden Preview Part X: User Registration
Garden Preview Part XI: Structure

Before development on Garden began, I spent a lot of time thinking about how to improve upon the plugin architecture adopted for Vanilla 1, and then I spent even more time doing test after test after test to see what really worked. In the end I realized that there can easily be more than one way to accomplish the task, so I’ve adopted a few standards, and I’ve left the code open to new methods of plugging in that some of you may decide to pursue. For now, I’ll talk about four different ways of plugging in.

1. Custom Events

Events are essentially what I mis-named as “delegation” in Vanilla 1. Any class that extends the class “Pluggable” has the ability to call $this->FireEvent('EventName'), and then plugins can attach to that event to perform some kind of operation. There should be no surprises here. There is a PluginManager class that picks up any defined plugins in the bootstrapper file (the file that includes core classes, defines constants, defines configuration settings, etc), and when the FireEvent method is called, it references the PluginManager class to see if there are any plugins that want to attach to the event name being fired. Of course it passes along some extra information that may be useful to the plugins as well:

public function FireEvent($EventName) {
  // Look to the PluginManager to see if there are related 
  // event handlers and call them:
  $this->PluginManager->CallEventHandlers(
     $this, 
     $this->ClassName, 
     $EventName, 
     $this->EventArguments
  );
}

At the time of this writing, there are no custom events in Garden. Custom events will be added on a case-by-case basis as the need arises (just like we did with delegates in Vanilla 1). Regardless, I haven’t yet had the need for any custom events in Garden because of…

2. Magic Events

Magic events are new in Garden, and they are based around some trickery I’ve come up with using PHP’s magic __call method. For those of you who don’t know what PHP’s __call method does, here is a quick breakdown: When you attempt to call a method on an object that does not have that method (PHP refers to these as “inaccessible methods”), the __call method is fired as: $Object->__call($Name, $Arguments) where $Name is the name of the method that was called but didn’t exist, and $Arguments is an enumerated array of the arguments passed to that method.

In Garden, I’ve taken advantage of __call to achieve what I’ve called “magic events”. There are two types of magic events in Garden: “Declared” and “Called”.

2a. Declared Magic Events

The theory behind declared magic events is that I can mis-name a method declaration by prefixing it with a pre-defined character (in Garden I’ve used “x” as the standard character). Then, when the class is instantiated, and that method is called without the “x” before the name, Pluggable’s __call method is fired. Within the __call method, Pluggable looks to the PluginManager to see if any plugins have attached to one of three automatic methods: Before, Override, and After. Let’s take a look at an example of how this might work:

// Imagine this class is a core Garden class
class MyFancyClass extends Pluggable {
    public function xTickle() {
        echo 'You just tickled my fancy!';
    }
}
$MyFancy = new MyFancyClass();
$MyFancy->Tickle();
// would typically render:
// You just tickled my fancy!

Now, let’s say I want to do something any time that method is called. For example, let’s say I want to prefix that message with a salutation like “Hey stranger, “. I could easily do that by creating a plugin like so:

// Define the plugin:
$PluginInfo['SuperFancifier'] = array(
   'Description' => 'Adds some niceties onto MyFancyClass.',
   'Version' => '1.0',
   'RequiredPlugins' => FALSE, // This is an array of plugin names/versions that this plugin requires
   'HasLocale' => FALSE, // Does this plugin have any locale definitions?
   'RegisterPermissions' => FALSE, // Permissions that should be added for this plugin.
   'SettingsUrl' => FALSE, // Url of the plugin's settings page.
   'SettingsPermission' => FALSE, // The permission required to view the SettingsUrl.
   'Author' => "Mark O'Sullivan",
   'AuthorEmail' => 'mark@lussumo.com',
   'AuthorUrl' => ''
);

class SuperFancifierPlugin implements IPlugin {
   public function MyFancyClass_BeforeTickle_Handler($Sender) {
        echo 'Hey Stranger, ';
   }
}

The first thing you see in this plugin is a definition for this plugin that is added to a “PluginInfo” array. There is a lot more information here than you might be used to coming from Vanilla 1. But, hopefully, it all looks fairly straightforward to you. I define the plugin’s name, description, author, author info, permissions, settings url, etc. All of these are customizable, and only the name, description, and plugin author are required. Everything else is there simply to help make your plugin more reliable and easier to implement. Furthermore, since a lot of these are new and changing every day, I’ll leave their explanation until the core is finished and the documentation is written. Let’s get back on track by looking at my actual plugin class code.

As you can see, I’ve created a class called SuperFancifierPlugin that implements the IPlugin interface. Using reflection, the PluginManager class can examine all declared classes to see which ones implement the IPlugin interface. After it finds all of them, it examines their methods. In this example, the PluginManager would find the SuperFancifierPlugin and it’s MyFancyClass_BeforeTickle_Handler method. It would break apart the method name based on the underscores and know that (a) it is trying to plug in to the “MyFancyClass” class, and (b) it wants to fire the method “Before” MyFancyClass’ Tickle() method.

The plugin manager knows all of this before MyFancyClass has even been included. It simply keeps a record of all plugins and all classes/methods they want to attach to. So, in the example above, after this plugin is included in the Garden bootstrapper, the following would happen:

$MyFancy = new MyFancyClass();
$MyFancy->Tickle();
// would now render:
// Hey Stranger, You just tickled my fancy!

I could take it a step further and add something afterwards like so:

class SuperFancifierPlugin implements IPlugin {
   public function MyFancyClass_BeforeTickle_Handler($Sender) {
        echo 'Hey Stranger, ';
   }
   public function MyFancyClass_AfterTickle_Handler($Sender) {
        echo "nWasn't that nice of you!?";
   }
}

Which would make the following happen:

$MyFancy = new MyFancyClass();
$MyFancy->Tickle();
// would now render:
// Hey Stranger, You just tickled my fancy!
// Wasn't that nice of you!?

And finally, I could completely change everything by overriding the Tickle method like so:

class SuperFancifierPlugin implements IPlugin {
   public function MyFancyClass_Tickle_Override($Sender) {
        echo 'I've overridden your fancy tickler.';
   }
}

Which would result in the following:

$MyFancy = new MyFancyClass();
$MyFancy->Tickle();
// would now render:
// I've overridden your fancy tickler.

2b. Called Magic Events

So, you’ve seen how a declared magic event forces Pluggable’s __call method to fire whenever the “real” (non-x’d) name of the method is called. Now let’s talk about the flipside to that coin: called magic events.

A “called” magic event happens when a class method is declared without the “x” before the name, but is called with the “x” before the name. For example:

class MyFancyClass extends Pluggable {
    public function Tickle() {
        echo 'You just tickled my fancy!';
    }
}
$MyFancy = new MyFancyClass();
$MyFancy->xTickle();
// would typically render:
// You just tickled my fancy!
// Unless I had my override plugin enabled, in which case it would render:
// I've overridden your fancy tickler.

So, what’s the difference between a called magic event and a declared magic event? It’s quite a large difference, actually. With a declared magic event, the plugin would be guaranteed to attach whenever that method is referenced. However, with a “called” magic event, the plugin would only attach if the method was called with the “x” prefix.

At the time of this writing, there are no called magic events in Garden. I am thinking that I will add them as necessary just like custom events. Furthermore, I’ve only used declared magic events with the Controller class’ Render and FetchView methods as these are the only places I’ve needed them so far. Of course, as time passes, I’m sure we will find more places to add all three types of events.

3. Function Overrides

I would have liked it if there were no functions in Garden. In my mind, functions should be in a class even if it is a static utility class that refers to the methods just like you would if they were functions. However, when I started writing Garden (and still today), PHP was lacking some things that I think would be necessary in order to put functions into a static utility class. For example, __callStatic isn’t production-ready, yet. So there would be no way to override functions if they were in a static class. So, as you may have seen in any of the other PHP-based frameworks out there, I’ve provided a last-ditch effort to allow plugin authors to override functions: function overrides.

Simply put, all functions in Garden are declared like so:

if (!function_exists('FunctionName')) {
   function FunctionName() {}
}

So, the plugin author has the ability to override any core function simply by defining it before the framework does.

4. Magic Methods

Finally, we come to magic methods. Imagine that there is a controller in Garden that doesn’t perform some task that you think is necessary. For example, what if I had created a UserController controller that only had methods to search for users, show users, and edit users. What if you wanted that controller to have a method to add a new user? That’s where magic methods come into play.

Magic methods in Garden essentially allow you to create new methods and add them to existing objects. They are created in much the same way that you plug into events. Using the MyFancyTickler class example above, what if I wanted to create a method on that class so that I could massage my fancy? I could create a plugin like so:

class MassageMyFancyPlugin implements IPlugin {
   public function MyFancyClass_Massage_Create($Sender) {
        echo "I'm massaging my fancy...";
   }
}

That’s it. With this plugin enabled, you could now do the following:

class MyFancyClass extends Pluggable {
    public function Tickle() {
        echo 'You just tickled my fancy!';
    }
}
$MyFancy = new MyFancyClass();
$MyFancy->Massage();
// And it would render:
// I'm massaging my fancy...

Conclusion

There are still things I could tell you about other ways to use the Pluggable class, but I think that’s enough for today. I know that some of you are probably worried that the magic methods will be too heavy on the server (this is a common complaint amongst the PHP developer community), but I’ve done my own homework that has helped me to both speed up my implementation of __call, and prove to me that (when used properly) it’s effects on speed are negligible. The bottom line is that when you see how it can be used, the benefits far outweigh the loss.

I seriously can’t wait to see what type of plugins the community comes up with for Garden. Imagine the possibilities!

Garden Preview Part VII: Ajax

Monday, December 22nd, 2008

Garden Preview Part I: Overview
Garden Preview Part II: Filesystem
Garden Preview Part III: Anatomy of a Request
Garden Preview Part IV: Views
Garden Preview Part V: Data
Garden Preview Part VI: Models & Forms
Garden Preview Part VII: Ajax
Garden Preview Part VIII: Plugins
Garden Preview Part IX: Roles & Permissions
Garden Preview Part X: User Registration
Garden Preview Part XI: Structure

I’ve chosen jQuery as the main javascript library for Garden. The jQuery core has a number of ajax-related methods that make ajax-based forms and functionality easy as pie. In order to help facilitate partial page loading & updating, I’ve made Garden’s base Controller class (the class from which all controllers are extended) accept a DeliveryType parameter on every request. Depending on the type of delivery being requested, a controller in garden will deliver all of a page, part of a page, or part of a page plus extra information as JSON.

At the time of this writing, there are four delivery types available:

DELIVERY_TYPE_ALL: Deliver an entire page (a standard request).
DELIVERY_TYPE_ASSET: Deliver all content for the requested asset.
DELIVERY_TYPE_VIEW: Deliver only the requested view.
DELIVERY_TYPE_BOOL: Deliver only the success status of the request as a boolean.

If no delivery type is provided in the request, DELIVERY_TYPE_ALL is assumed. In my programming for Vanilla 2 and the main Garden management screens, I’ve found that 99% of the time I either use DELIVERY_TYPE_ALL or DELIVERY_TYPE_VIEW. The four delivery types are just constants defined as:

define('DELIVERY_TYPE_ALL', 1);
define('DELIVERY_TYPE_ASSET', 2);
define('DELIVERY_TYPE_VIEW', 3);
define('DELIVERY_TYPE_BOOL', 4);

In order to made the controller deliver content other than DELIVERY_TYPE_ALL, you would have to append the request url (or post data) with DeliveryType=3 (or whatever type of delivery type you want). The controller will grab this value from whatever collection you send it in and then know how to handle the request.

In all four delivery types, the standard response for the controller is to simply take the requested data and spit it to the response. The only exception to this rule is if there is a form posted to the controller. In the case of a form being posted to the controller, it will take the response xhtml and place it into a JSON array along with a couple of other standard bits of information and any extra information that you may want to add.

Let’s take a look at some examples of how the delivery type works.

Form Popups

users

In a DELIVERY_TYPE_ALL request, you could be looking at a list of users with an “edit” link next to each of them. You click the edit link, and it takes you to a page that presents you with a form where you can edit all of their information. If you were editing my account, this url might look something like: http://localhost/garden/user/edit/mark

This means that you’ve called Garden’s $UserController->Edit('mark'); method, and Garden is going to fetch the /garden/views/user/edit.php view file, place it in the views/default.master master view file and deliver everything to the screen.

I’ve created a jquery “popup” plugin for Garden that allows you to turn any link in Garden into a view-based popup by applying a “Popup” class to the anchor tag of the link. So, if I had placed that class on the “edit” link next to my username, here’s how the request would be handled by the controller:

The jquery-based popup plugin appends a “DeliveryType=3″ parameter to the request url and then sends the request. Garden’s $UserController->Edit('mark'); method is called, and Garden fetches the /garden/views/user/edit.php view file. At this point it only sends the view back to the popup plugin as a string of xhtml. The popup plugin takes the code from that view file and places it into an element on the page, positioning it above the existing page content. So, without loading a new page I’ve now been presented with the edit user form in an in-page popup.

edituser

If I then make changes to the inputs and submit the form, the popup plugin once again hijacks this request, making it an ajax-based request. The controller sees that it only needs to deliver the view once again, and it also sees that a form has been posted back. So, it takes the resulting xhtml and places it into a JSON array to be sent to the response. It also adds extra information to the json array like: (1) a boolean value indicating if the form was saved, (2) a status message, (3) a redirect url, etc. Using these json values the popup can then decide if it should re-present the form with any errors that may have occurred, or hide the form and update data on the underlying page.

Progressive Data Loading

One of the major changes I’ve been working with in Vanilla 2 is progressive data loading. In a standard, non-javascript-based request, I’ve made it so that at the end of a page of comments the user is presented with a “show X more comments” button. When that button is clicked, it takes you to the second, third, nth page of comments.

However, if javascript is enabled, jquery will hijack those button clicks and make the request as a DELIVERY_TYPE_VIEW. It then takes the next page of comments and appends them to the existing comment list directly in the page.

These are just two examples of how ajax is integrated into the Garden core. There are a number of other ways that it is used, and I’m adding more methods every day. The ajax code has already been through many revisions, and I anticipate that once the code goes public there will be javascript gurus in the community who will have a lot of great ideas for how to optimize and improve upon what I’ve done.

Next

I know that some of you have requested to hear more about users, administration, and permissions. I’ve been hesitant to move onto those topics because they are more about user interface than the code-behind, and I still don’t have a solid design in place (hence the cropped screenshots above). In the first few weeks of the new year I am going to be locking down a general design for Garden and Vanilla with the help of some colleagues. So, look forward to some actual screen-shots of the application(s) in action. Until then, however, I think it’s best to keep my pocket-protector firmly planted on my chest and move on to plugins next week.

Garden Preview Part VI: Models & Forms

Tuesday, December 16th, 2008

Garden Preview Part I: Overview
Garden Preview Part II: Filesystem
Garden Preview Part III: Anatomy of a Request
Garden Preview Part IV: Views
Garden Preview Part V: Data
Garden Preview Part VI: Models & Forms
Garden Preview Part VII: Ajax
Garden Preview Part VIII: Plugins
Garden Preview Part IX: Roles & Permissions
Garden Preview Part X: User Registration
Garden Preview Part XI: Structure

Models

The theory of a Model in MVC is that it is an object representation of the data being manipulated. As you’ve seen in the last Garden preview, however, the actual object representation of the data comes from the DataSet class in the form of a php stdObject. So, as you may have guessed already, in Garden the model isn’t a representation of the data.

In Garden, a model relates directly to a table, and (with the help of the database object) allows you to retrieve information from the table, enforce the schema of that table on data being manipulated, and put data into the table. The real power of the Model class in Garden comes from it’s ability to examine the table from which it was created, and understand the data types and requirements for putting data into that table. When combined with Garden’s Validation and Form classes, this makes for a very powerful set of tools.

The Model class itself is quite simple, and can be used on any table in the database. Let’s take a look at a very basic example of how a model could be used to get some data from a database, validate data, and update data.

// Create a validation object to handle 
// validation issues that the model will 
// encounter:
$Validation = new Validation();

// Create a new model based on a table 
// in the database called "Blog":
$BlogModel = new Model('Blog', $Validation);

// Retrieve a DataSet from the Blog table:
$BlogData = $BlogModel->GetWhere(array('BlogID' => '12'));

// Grab the first row of the dataset as an 
// associative array:
$Blog = $BlogData->FirstRow('', DATASET_TYPE_ARRAY);

// $Blog now contains every column of the 
// "Blog" table where BlogID == 12. Let's 
// change something:
$Blog['Title'] = 'Some blog title';

// And save it:
$BlogModel->Save($Blog); // Validates

// And let's try to insert something that 
// we know shouldn't go into the database:
$Blog['BlogID'] = 'Not an Integer!';

// And save it:
$BlogModel->Save($Blog); // Doesn't validate

When the model’s “GetWhere” method is called, it does a very simple “select * from Blog where BlogID = 12″ query that returns all of the columns from that table into a dataset. At this point, the model still doesn’t know anything about the structure of the table.

When the model’s “Save” method is called, the first thing it does is uses the Database object to get information about the table so that it can define the table’s schema. It looks at each column’s data types, isnullable, default values, keys, etc. Then it uses the validation object to build up a set of rules for each column. Finally, it examines the $Blog that was passed as it’s first argument, matching up associative array keys with column names, and then checks each field against the rules automatically defined for that table. As it encounters problems, it builds up a set of validation results that can then be used however you wish (typically they are consumed by Garden’s form object and displayed on the screen).

So, with just a few lines of code, I’ve grabbed data from the database, altered it, and saved it – making sure that no invalid data is inserted into the database, all exceptions are caught, and results can be delivered to the user:

print_r($BlogModel->Validation->Results());
// Prints:
Array (
    [BlogID] => Array (
            [0] => ValidateInteger
        )
)

This means that the “BlogID” field has encountered a problem when attempting to validate that the BlogID value was an integer. If there had been other errors for that column, they would have also appeared, for example:

// Empty value is also incorrect
$Blog['BlogID'] = ''; 
$BlogModel->Save($Blog);
print_r($BlogModel->Validation->Results());

// Prints:
Array (
    [BlogID] => Array (
            [0] => ValidateRequired,
            [1] => ValidateInteger
        )
)

The validation object will always collect as much information about what is wrong with the data as possible. It is then up to the developer what to do with that information. Luckily, 99% of the time the developer will just let the Form handle the validation results.

Forms

In order for the database, models, validation, & datasets to shine, we need to get the information out and editable by the users. This is where the Form class comes into play.

Let’s take a look at an actual example of how the controller, model, validator, and form work together. Let’s say we get the following request:

/bloggingtool/post/new

Which is the same as calling the following controller in an imaginary “bloggingtool” application:

$Post->New();

My “New” method on the post controller would contain:

public function New() {
   $Validation = new Validation();
   $BlogModel = new Model('Blog', $Validation);

   // Set the BlogModel on the form.
   $this->Form->SetModel($BlogModel);

   // If the form has already been posted back...
   if ($this->Form->AuthenticatedPostBack()) {
      // Attempt to save the form values
      $BlogID = $this->Form->Save();

      // If it saved, redirect to the new entry:
      if ($BlogID !== FALSE)
         Redirect('/bloggingtool/entries/'.$BlogID);

   }
   // Render the form
   $this->Render();
}

The form’s Save() method calls the model’s Save() and then takes any validation results that came out of it. If the save was successful, the model would have returned the id of the record inserted (or updated). If not, it could take all of the validation results and write them to the screen for the user to see.

That’s really all there is to saving a bunch of data to the database. You might be wondering: What fields were actually saved? That all depends on what you put on the form.

The Form class is a “user interface” class, which means that a large number of it’s methods actually return xhtml. As you can imagine, methods on the form object would include things like:

// This code would likely appear in a view 
// that gets rendered when $this->Render() 
// is called in the example above.
echo $this->Form->Open($FormOptionsArray);
echo $this->Form->Errors();
echo $this->Form->TextInput('Title');
echo $this->Form->TextBox('Body');
echo $this->Form->Close('Save');

In this example, you can see I’ve referenced two fields on the Model that is being manipulated: Title and Body. When the form’s “Save” method is called above (and the Model’s “Save” method is called therein), the model validates and attempts to save the data. If one of these two fields were required, it would return a validation result that would then be written to the screen by $this->Form->Errors(). Furthermore, if there were a field on the “Blog” table that were required and not present on this form, it would have a validation result for that as well.

What if we were editing a blog post instead of creating a new one?

public function Edit($BlogID = '') {
   $Validation = new Validation();
   $BlogModel = new Model('Blog', $Validation);
   
   // Load the blog being edited
   $Blog = $BlogModel
      ->GetWhere(array('BlogID' => $BlogID))
      ->FirstRow();
   
   // Set the BlogModel on the form.
   $this->Form->SetModel($BlogModel);
   
   // Make sure the form knows which item we are editing.
   $this->Form->AddHidden('BlogID', $BlogID);

   // If the form has NOT been posted back...
   if ($this->Form->AuthenticatedPostBack() === FALSE) {
      // Set the blog on the form
      $this->Form->SetData($Blog);
   } else {
      // Attempt to save the form values
      $BlogID = $this->Form->Save();

      // If it saved, redirect to the new entry:
      if ($BlogID !== FALSE)
         Redirect('/bloggingtool/entries/'.$BlogID);

   }
   // Render the form
   $this->Render();
}

I load the blog and set it’s data onto the form using $this->Form->SetData(). At that point the form takes over and knows to either (a) render the existing data if the form has not been posted back, or (b) render the postback data otherwise. And since I added the BlogID to the form’s hidden field collection, the model will know that it should update a blog row instead of insert a new one.

Conclusion

That’s a lot to swallow in one big gulp. For that reason, I’ve really only shown you the most basic of examples. Of course there are times when a new Model(‘TableName’) isn’t going to handle everything you need. In those cases you can create your own custom model class that extends the base Model class and delivers all of your custom methods and functionality. Furthermore, you don’t have to be tied to the form object so closely if you don’t want to. You can always pull back and handle all of your validations directly with the model. You can also create new custom validation rules that the validation object can apply to fields for more non-generic data validation.

Next

At this point I’ve covered a lot of the core functionality. If you have any requests for things you’d like me to elaborate on, or other parts of the framework you are interested in hearing about, please let me know. Otherwise, I’ll move on to ajax next.