Arbit aims to provide a decent modern extensible multi project tracking tool. Features start with issue tracking and wiki and do not stop before code analysis and translation management.
CouchDB is a document based database. From their website:
CouchDB is a document-oriented, Non-Relational DataBase Management Server (NRDBMS). The CouchDb Quick Overview has a high level overview of the CouchDB system.
More detailed information can be found at here.
To connect to your CouchDB instance simply use the phpillowConnection class like shown here:
phpillowConnection::createInstance('localhost', 5984, 'user', 'password');Once created this connection will be used in your document and view classes automatically.
As noted above the central object we have to deal with are documents.
All documents extend the abstract base class phpillowDocument. A complete model defining a blog entry could look like:
class myBlogDocument extends phpillowDocument
{
protected static $type = 'blog_entry';
protected $requiredProperties = array(
'title',
'text',
);
public function __construct()
{
$this->properties = array(
'title' => new phpillowStringValidator(),
'text' => new phpillowTextValidator(),
'comments' => new phpillowDocumentArrayValidator(
'myBlogComments'
),
);
parent::__construct();
}
protected function generateId()
{
return $this->stringToId( $this->storage->title );
}
protected function getType()
{
return self::$type;
}
}The static property $type defines the type of the stored document and should be unique in the whole application. If you are implementing a module, prefix this type with the name of the module, like "blog" in this example. If you happen to use a PHP version prior 5.3 you have to return the document type in each of your document classes like shown above. 5.3 and above users can use a more generic approach with returning 'static::$type' in a base document class.
The array $requiredProperties defined the properties, which are mandatory to be set. The properties itself are defined in the $properties property, which is initialized in the constructor of the document. We associate a validator with each property which validates the input set on the document. There are quite complex validators, like the phpillowDocumentArrayValidator shown here, which will be described later, which are all documented in the generated API documentation.
The last thing you need to define is the generation of the document ID. An ID in CouchDB needs to fulfill some requirements, which are ensured by using the protected method stringToId(). Normally you use one somehow unique property of the document. If this is not entirely unique the document handler will append something, so that it will get unique. Just return null if you want CouchDB to give you an unique id for the document.
With a document definition like above you can use the document in your code as simple as:
$doc = new myBlogDocument();
$doc->title = 'New blog post';
$doc->text = 'Hello world.';
$doc->save();With the call to save() the document will be generated and stored in the database. After this a new magic property is available for the document:
echo $doc->_id;
> blog_entry-new_blog_postUsing documents directly this ID is the way to fetch the document back from the database, like:
$doc = new myBlogDocument();
$doc->fetchById( 'blog_entry-new_blog_post' );This call retrieved the above document back from the database. The magic CouchDB properties _id and _rev (for revision) are set for the document. Beside the defined properties another property has been created by the wrapper, called revisions, which contains all old (and the current) revisions of the document:
echo $doc->revisions[0]['title'];
> New blog postIf you now change a property on the object and store it again in the database the old revision will also be stored in the database, so that no information is lost on change. This behaviour may be deactivated by setting the $versioned property to false.
Views in CouchDb are a way to index and access documents by their properties, perhaps filtered, or by complex self defined keys. Views for our documents extend the view base class phpillowView, and implement the view logic as EcmaScript, executed on the server (currently using the SpiderMonkey implementation). A view definition for our blog entries could look like:
class myBlogView extends phpillowView
{
protected $viewDefinitions = array(
// Index blog entries by their title, and list all comments
'entries' => 'function( doc )
{
if ( doc.type == "blog_entry" )
{
emit( doc.title, doc._id );
emit( [doc._id, 0], doc._id );
if ( doc.comments )
{
for ( var i = 0; i < doc.comments.length; ++i )
{
emit( [doc._id, 1], doc.comments[i] );
}
}
}
}',
);
protected function getViewName()
{
return 'blog_entries';
}
}For detailed information how views work, you should read the CouchDB documentation on views, but the here implemented shows some nice features of CouchDB views.
All view definitions are stored in the property $viewDefinitions and are automatically written to the database. The view has a name, which is used to identify the set of views in the database and does not really matter.
In one view the defined EcmaScript should only operate on one type of documents, but is not forced to do so. The CouchDB function emit() takes a key and some content as parameters and indexes the given content by the given key. The first call to map indexes all blog entries by their title, a simple string to string index. As views are also completely generated you should not store the entire documents, but only the ID, as shown above. You may now fetch the document by its original title:
$doc = myBlogView::entries( array( 'key' => 'New blog post' ) );The next two map functions create a complex index, so you may retrieve the IDs of one blog entry and all comments related to that blog entry with one query:
$docs = myBlogView::entries( array(
'startkey' => array( 'blog_entry-new_blog_post', 0 ),
'endkey' => array( 'blog_entry-new_blog_post', 1 ),
) );For details why and how this works you may want to read the section on view collation in the CouchDB wiki.
The manager provides a central registry for CouchDB documents and views. You may set and overwrite the document class for one document type, or query this document class directly, whatever class has been set for it, like:
phpillowManager::setDocumentClass( 'blog_entry', 'myBlogDocument' );
$doc = phpillowManager::createDocument( 'blog_entry' );
// ...
$doc = phpillowManager::fetchDocument(
'blog_entry', 'blog_entry-new_blog_post'
);
// ...The same is true for views.