Knickers: Change your underwear!

Example: Task List, Part 2 (INCOMPLETE!)

In the previous chapter, we got our tasklist application started. Lets continue; in this lesson we want to:

Make a better List/Task interface

While it is nice that class builder created the basic pages for lists and tasks for us, it would be better if you could add tasks directly on the list admin page.

Once we tell Knickers about the relationship between two tables, showing the related table data on the other's admin page is pretty easy. Now, the task Thing already knows about lists, because it was created after lists; but since lists were created first, we need to help out a little.

Open common/cls/Modeling/Thing_List.class.php and add this after the end of the $hasA member variable:

var $hasMany = array
	(
		'TASKS' //@docarray_element GetableFields Related TASKS, a Thing_Task
	);

We also need to tell the list ComponentFinder about the relationship; open common/cls/Component/ComponentFinder_List.class.php and add this within the $relatedFinders member array (remember to add a comma after the CREATOR entry!):

	'TASKS' => 'ComponentFinder_Task'

Now we can show the tasks for a given list just by modifying the list admin template; open common/tpl/html/Panel_ListAdmin.tpl and add this after the Name div:

	<div>
		<label for='{LIST.NAME.DOMID}'>Tasks:</label><br/>
		<ul>
			{|LOOP|LIST.TASKS}
				<li>{TASKS.DESCRIPTION}</li>
			{/|LOOP|LIST.TASKS}
		</ul>
	</div>

Refresh your list admin page, and you should see the task you added for the current list! This shows some of the power of Knickers' template parser, called OutputGenerator ("OG" for short).

That's neat, but can I add tasks here too?

If all you wanted to do was allow users to edit the description of existing tasks, you could change the {TASKS.DESCRIPTION} tag to {TASKS.DESCRIPTION.INPUT} and voila! you have inputs instead of just a list.

Adding new tasks, however, is a slightly different proposition, but Knickers can help here too. Knickers has a mechanism for managing a list of relatives on the interface, called a "dynamic lister", which is part of ComponentFinder's "view" mechanism. Open up common/cls/Component/ComponentFinder_List.class.php, and within the $views member array, add:

	'TASK_LISTER' => array
		(
		'relative' => 'TASKS',
		'relativeView' => 'VIEW_OF_TASK',
		'staticCount' => 1,
		'showDynamic' => TRUE
		)

Now, we need to modify our task view to be in input mode, so open common/tpl/html/view_of_task.tpl, and change it to (we will want to do this differently if we have a selector of tasks, but that's for another day):

{COMPONENTFINDER_TASK.DESCRIPTION.INPUT}

Now, go back into the list admin template (common/tpl/html/Panel_ListAdmin.tpl), and replace the <ul> containing the TASKS loop with:

{LIST.TASK_LISTER}

...and when you reload the page, you should notice the existing tasks are listed, but there is also an empty input, ready to create a new task for this list!

Adding Friends

In our application, a "friend" is another user that is connected to our account. This will help illustrate a different type of model relationship that Knickers can help with.

With lists and tasks, a list "has many" tasks - it is a "one-to-many" relationship. Conversely, a task "has a" list; it is a "many-to-one" relationship. Another common relationship is a "many-to-many" relationship, which is what users-to-users (friends) are. Many-to-many relationship require a linking table, so let's set that up:

cd /home/yourname/tasklist
[KNICKERS_ROOT]/scripts/create_table.php --class-builder user_friends user_id:Integer friend_id:Integer

The class builder will stop on FRIEND_ID, but this is really just a user, so enter "n" and then "Thing_User".

When that is complete, we need to tell the user Thing about the relationship. Open common/cls/Modeling/Thing_User.class.php and add this after the end of fields array:

var $hasMany = array('FRIENDS' => array('through' => 'Thing_UserFriend'));

Since the system doesn't really know that FRIENDS is basically an alias for Thing_User, we need to add the following to cfg/Thing.cfg.php:

$THING_EXTERNAL_CONFIG['CLASSNAMES']['FRIENDS'] = 'Thing_User';

.....to be continued....