Iteration 2 of the contract that's given me the opportunity to improve KnowledgeTree's insides was made up of implementing transactions on all document functions, adding entries into the history of documents that moved, bulk import and the addition of tree-like metadata.
The smallest first - the specification required that moves add information into the history log of the document. Simple enough.
The tree-like metadata is probably the most obvious change, since it's the most visible.
The requirement for the tree-like metadata was that a metadata field should be created that allows the choice of a specific value from a lookup navigated by a tree hierarchy. The branches aren't themselves nodes, only the leaves.
So, first you edit your lookup field, and assign categories (which can be nested):
When editing a field for a first time, you see the top-level categories and items:
As you expand categories, you see the categories and items within:
When you re-edit a field with an existing value, the tree automatically expands as necessary to allow you to see the existing value:
On to the biggest back-end affecting part - transactions. When KnowledgeTree 1.2 was released, MySQL 4 wasn't something the developers could rely on to be used by the users of KnowledgeTree. Even now we get people using MySQL 3.23. As part of this iterations' transaction work, document manipulation actions were centralised into utility classes (previously they lived in the controller/presentation files for that part of the web page, ick!).
While I was centralising moving, I implemented folder moves, as they are the obviously missing component.
Database transactions are actually rather easy. By requiring the use of transaction-capable databases if one wants to have transaction-capable KnowledgeTree, most of the work is pushed onto the database by starting and committing or rolling back of transactions. I always suspected that would be the easy part.
However, the really hard part is keeping consistent state on the filesystem. KnowledgeTree 2 stores files on the filesystem in a filesystem hierarchy matching the repository hierarchy as the only option. As you can imagine, transaction-safe moving is quite hard if you suddenly have an error half-way through moving a folder or bunch of files.
KnowledgeTree 3 solves this in two ways. Firstly, moves of entire folders was implemented (as above) using the most effective means of moving folders on the platform - on at least Linux, it is atomic to move a single directory. That reduces the amount of times multiple documents are moved, and adds a new feature - bonus.
Secondly, the entire content storage system was abstracted, allowing for files to be stored not in the same hierarchy as the repository. With the storage manager keeping track where the file is on the filesystem, and moves not affecting the filesystem at all, the problem is avoided. In addition, files left over from aborted additions and bulk imports won't get in the way of future additions and bulk imports trying to put things in the same location. In all, avoiding the problem altogether. (A cleanup script can notify the administrator of left-over files to be deleted, or just delete them without much worry.)
In iteration three (coming on Tuesday), I implemented per-request transactions in the dispatcher system of KnowledgeTree (more on both of those later), which means that all actions in KnowledgeTree will soon be transaction-safe. Either your request will totally work, or not work at all. When we can eventually use PHP5 exceptions in KnowledgeTree (i.e., in a few years when most people are using PHP5), the whole process will be a lot cleaner.