New Roadmap for Artisan System

Posted by Vic Cherubini on February 18, 2010

This is a valid article, and is considered technically accurate up to Feb. 21, 2010

I recently rejoined the ranks of the working at a great company. As a result, I am not as concerned about trying to get contract and freelance work and I can now concentrate on my personal projects more. In the last 6 months I spent a lot of time working on other software, and while it paid the bills, I’m anxious to get back to my own.

My first real piece of Open Source software I wrote is my PHP Framework Artisan System. I haven’t had a chance to work on much since it was originally released, only changing a few things and undergoing some reconstruction since. I’ve now written a new roadmap for 2010 in the direction I’d like to take Artisan System.

2010 is going to bring a new change to Artisan System, and the roadmap includes the following items.

  • System fully under test (SUT). A new test suite will be written for all existing functionality, and new development will be done through tests.
  • Controller mechanism will be made fully RESTful. You will be able to access Controllers through a URI via PUT and DELETE methods. GET will list all items in a collection, PUT will update an item in a collection, POST will create a new item in a collection, and DELETE will delete an item in a collection.
  • A new design pattern called Interceptors will be introduced. Interceptors intercept the output of objects from a Controller to return them in the format that the Accept header asks for. HTML will be the default, but XML, JSON, JavaScript or other formats will also be allowed. Thus, if you wanted to return an object from a Controller that only includes a certain number of fields, a custom Interceptor could handle that, rather than having the Controller handle it.
  • The Controllers will read the Content-Type header to determine the format of the input.
  • The appropriate HTTP response code will be sent after a call to a URI. 200 for HTTP OK, 404 for not found, etc.
  • Everything will be time tested and sped up if necessary.
  • My other framework, DataModeler, will be integrated with Artisan System. They’ll become a single framework.
  • Redis support, and potentially support for other NoSQL databases will be added.
  • The codebase will be Doxygenated.
  • The Router will support routing tables for vanity URL’s.
  • A new website and community will be launched to create a strong developer community. The website will include a bug tracker, wiki, and forum.
  • Videos, screencasts, tutorials, and podcasts will be released to help support this effort.

I’m really looking forward to seeing what I can create. Of course, I’ll appreciate any help I can get. You can fork the Artisan System project on Github and help develop it. After I get the new website up and running, you’ll be able to access the bug tracker, wiki, and forum. From there, we’ll correspond development efforts.

Working with Artisan System – Basics

Posted by Vic Cherubini on December 14, 2009

This is a valid article, and is considered technically accurate up to Feb. 21, 2010

I’m incredibly proud of my PHP Framework Artisan System. It’s gone through a lot of revisions over the last year, and its never really picked up. Part of the reason is I haven’t promoted it much, but another part is that no one knows what to do with it. As the problem with a lot of open source software, there’s a lack of documentation to support it.

This occurred to me after I made a post on Hacker News about my Amazon S3 Backup Utility. Immediately, I had 7 new followers of it on Github.

I want to make a difference with my code, and I want to get the word out about Artisan System. It’s incredibly simple, but powerful. I’ve started this series of posts to help people start working with Artisan System.

Let’s get started.

Installation

Start by creating a new directory structure in your web root to store all of the files in. Download the latest tarball, untar it, and then rename the resulting directory to Artisan.

cd /var/www/
mkdir artisan-system -p
cd artisan-system
wget http://github.com/leftnode/Artisan-System/tarball/0.5.4
tar -xvzf leftnode-Artisan-System-cc2af85.tar.gz
mv leftnode-Artisan-System-cc2af85 Artisan
rm leftnode-Artisan-System-cc2af85.tar.gz

Artisan System is now installed. You could equally clone it from Github as well and use the clone.

Databases

The first thing you’ll want to explore is how to connect to a database. Until recently, Artisan was going to support multiple databases. After some reflection on the direction I wanted to take the project, I removed the potential support for additional databases and just kept MySQL. Adding a new database adapter would be simple. Furthermore, the current database adapter could be updated to using PDO to automatically support additional database wrappers.

Connecting

Connecting to a MySQL database is simple.

There no longer is any formal configuration object in Artisan System. Configurations are now simple arrays. You can optionally pass in the port to the configuration array, but Artisan selects the MySQL port, 3306, by default.

This example is the simplest of examples on how to connect and then disconnect to a specified database. If the connection fails, the exception is caught and reported.

Querying

Querying the database is just as simple with the query() method in Artisan_Db. The query() method takes a raw SQL string and executes it. It does not take any precautions to prevent SQL Injection attacks. In general, you should not use the query() method directly.

Querying With Methods

Artisan System provides a much more robust system for querying a database: methodized querying. Methodized querying builds a query through an object via a chainable object. The most common query types (SELECT, INSERT, UPDATE, DELETE, and REPLACE) are included and accessible through the Artisan_Db object.

You should use methodized querying for several reasons.

  1. Its safe. The data is automatically escaped to prevent SQL Injection attacks.
  2. Its fast. It’s obviously not as fast as querying with a direct SQL string, but its faster than PHP’s parameterized querying.
  3. Its semantical. Building a query reads like writing a sentence.
  4. Its abstract. The classes behind the query actually build the SQL itself, so porting it from one database system to another would be simple.

Querying with methodized querying is simple and straightforward. One of my favorite features is to be able to select a single row and get a specific value back. It takes what would normally be 3 to 4 individual commands to a single one.

Take the time to explore Artisan System. You’ll find a powerful, compact PHP Framework to really help you build a web application quickly. In the next article, we’ll cover the basic Model-View Controller Pattern in Artisan System.

Working With git Or: Notes To Myself

Posted by Vic Cherubini on December 08, 2009

This is a valid article, and is considered technically accurate up to Feb. 21, 2010

I’ve read Daniel Miessler’s blog for a while now as its popped up on different sites like Reddit and Hacker News. I never officially subscribed to it in any formal capacity, but yesterday he had an article on using git to manage his site. The article taught me a lot about git, but I was more interested in the footnote of another article he wrote.

[ If it seems like this post is a note to myself, that's because it is. :) That's how the entire site got started, actually. ]

I liked that. For the longest time, I felt like this blog (or my writing online) had to be very long, very drawn out, thought out entries. I think I can safely change that now. It’s my writing online and I want both entries: long very well thought out ones introducing new ideas, and short ones that are simply notes to myself or small snippets of code or ideas.

I like learning something new each day. Today, I learned the basics of git submodules. Similar to Subversion svn:externals, git submodules let you have additional repositories as sub-directories to your main project. I used svn:externals a lot when I did everything with Subversion. Rather than keeping the Artisan System framework installed at, say, /usr/share/artisan-system/, I always like to install it with the project I’m working on. That way, I can create an immediate release with all of the code in a single location. Additionally, if I come across a bug as I’m developing, I can immediately fix it there, commit to the HEAD of Artisan System, and then tag it and push it to GitHub.

If you have a project hosted at GitHub with the clone URL: git@github.com:leftnode/Artisan-System.git and you want to set it as a submodule, git handles this easily.

# Ensure you are at the root of your git project, i.e., where the .git directory is
 
# This makes the directory lib/Artisan/ a submodule repository
git submodule add git@github.com:leftnode/Artisan-System.git lib/Artisan
 
git commit -a -m "Added Artisan System framework as a submodule."
git submodule init

If you make a change to any of the files in the submodule, be sure to commit them first. Then commit the parent project to ensure both are up to date.

# In the submodule directory
cd lib/Artisan/
vim Iterator.php
# hackity hack hack
git commit -a -m "Updated Iterator.php with something or other."
git tag 0.5.2 -m "Creating the 0.5.2 tag with some changes to Iterator.php."
git push origin --tags
cd ../../
git commit -a -m "Updated the Artisan System submodule."
git submodule status

The last output will show you your submodule is at the latest tag.

 07bd774e56d645844d9eb3691cea706a065288ee lib/Artisan (0.5.2)

You can read a much more in depth guide at Fraser Speirs blog.

Artisan System 0.5.1 Released

Posted by Vic Cherubini on December 02, 2009

This is a valid article, and is considered technically accurate up to Feb. 21, 2010

A very small bug-fix release was just made. You can grab it at GitHub: http://github.com/leftnode/Artisan-System/tarball/0.5.1

It consisted of a single character change to View.php to make calling makeUrl() work properly.

Artisan System Commits Seppuku

Posted by Vic Cherubini on December 02, 2009

This is a valid article, and is considered technically accurate up to Feb. 21, 2010

I had a huge opportunity to really show off the power of Artisan System while building Prospect Vista. The overall development of Prospect Vista as it exists today was a total of 3 months. In that time, there was one major rewrite, and 1 month of updates after the initial release. For a site that does so much, building it on Artisan System was a big decision for me.

There were other, more complete frameworks, but I really had a case of Not-Invented-Here syndrome, and I wanted to build everything myself. Plus, I had spent nearly a year building Artisan, and wanted a way to show it off.

So, I built Prospect Vista on the 0.3beta of Artisan System. This was also a growth period for Artisan as it gave me a way to fine tune some minor things (mainly with the model-view controller). The site launched, and its been a great success.

After that though, there was just this feeling that there was so much waste. I didn’t use half of the classes in 0.3beta, and I never had for any other system I had built. For example, I had never used the RSS, Server, Shipping, or Customer classes (even though there was some really cool code in there). The Config class was generally a wrapper for stdObject and Artisan_Vo. The Authentication class was no longer needed because it was too basic, for any non-trivial authentication system (especially database backed ones), more code would be in the hook to validate the user than in the original query just to load them up. The individual Validate classes were overly verbose, and each class could be made into a single function.

I removed the following classes in the 0.5 release:

  • Auth
  • Config
  • Customer
  • Log
  • Rss
  • Server
  • Shipping
  • Validate (made into functions)
  • Any non-MySQL database class, lets face it, I’ve only used MySQL.

Furthermore, all of the directories were removed, and the filenames were renamed to map to their meaning. For example, all of the Db classes were moved to Db.*.php. All of the Functions were moved to Func.*.php, and so on. I also removed a lot of the unnecessary Doxygen comments.

Artisan System’s file structure is now comprised of:

  • Cache.php
  • Controller.php
  • Db.Builder.php
  • Db.Iterator.php
  • Db.php
  • Db.Result.php
  • Exception.php
  • Func.Array.php
  • Func.Crypt.php
  • Func.Db.php
  • Func.Input.php
  • Func.Library.php
  • Func.Validate.php
  • Iterator.php
  • Registry.php
  • Router.php
  • Session.Db.php
  • Session.php
  • Sql.Delete.php
  • Sql.Insert.php
  • Sql.php
  • Sql.Select.php
  • Sql.Update.php
  • Template.php
  • Validator.php
  • View.php
  • Vo.php
  • Xml.php

This is the original vision I had for Artisan System. It went from nearly 10000 lines of code to a succinct 2597. Using the framework is very simple. You can include the entire framework in your application with barely a dent in performance.

It includes a full MVC layout engine that has the ability to handle URL routing, complex Controllers, and simple Views.

Grab the 0.5 release from Artisan’s Github page. I will add some tutorials in the future on how to use the new, slimmer framework.

Versioned Objects in Artisan System 1

Posted by Vic Cherubini on December 01, 2009

This is a valid article, and is considered technically accurate up to Feb. 21, 2010. Versioned objects were removed in Artisan System, but will make a re-appearance soon.

A new feature in Artisan System 0.3a1 are versioned objects. Versionable objects have been mentioned in several previous posts, however I am officially announcing them now. Additionally, I want to hear if the community in general believe they are a neat or useful idea.

A versionable object is one who stores historical information about the changes in data from within that object. It works very similarly to how source control works with source code: changes made over time are tracked, and thus, you can go back to a previous change should you break something. Versionable objects in Artisan System 0.3a1 are stylistically based off of Subversion.

Code Snippet

Currently, the only object that can be versioned right now is the Customer class. I did it there simply because I had no plans to write a versionable object, I was working on the Customer class when I had this idea, so I simply implemented it there first. I plan on pushing out the idea of a versionable object to a generic class, where one could create an object outside of the versionable object, pass it to the versionable object, and automatically track versions. Essentially:

require_once 'Artisan/Db/Adapter/Mysqli.php';
require_once 'Artisan/Customer.php';
require_once 'Artisan/Versionable.php';
 
// Assume $config_db was defined elsewhere and contains connection information
$db = new Artisan_Db_Adapter_Mysqli($config_db);
$db->connect();
 
// Load up customer ID #10
$customer = new Artisan_Customer(10);
 
// Make the customer versionbale now, loading it up at the HEAD revision
$versionable = new Artisan_Versionable($customer);
$versionable->setStorageDb($db);
 
$customer->firstname = "newfirstname";
$customer->age = 24;
 
// Must use $versionable to write the object's historical data, just like you
// must use `svn ci` to check in changes.
$versionable->write();
 
// However, you can simply call write() directly to save a small amount of changes.
$customer->write();

The above code is only a sample, and will not work now. I have not fully designed the generic Versionable object, but I believe it will work similarly to the code above. This example will show the versionability with the Customer class.

require_once 'Artisan/Db/Adapter/Mysqli.php';
require_once 'Artisan/Customer/Db.php';
 
// Assume $config_db was defined elsewhere and contains connection information
$db = new Artisan_Db_Adapter_Mysqli($config_db);
$db->connect();
 
// Create a new customer object that stores it's data in the database, this
// will eventually be changed to have all customer data stored in the database
// by default because honestly, where else are you going to store customer data?
$customer = new Artisan_Customer_Db($db);
 
// Load up customer ID #10 at the HEAD revision.
$customer->load(10);
 
$customer->lastname = "Fisher"; // Update the lastname to Fisher
$customer->age = 19;
$customer->tax_id = "19300x9d93";
 
$c_data = array(
 'favorite_book' => "The Art of Computer Programming"
);
 
$customer->setFromArray($c_data);
 
unset($customer->dateofbirth);
 
// Create a new revision, assume <em>lastname</em> and <em>age</em> have already been created,
// and thus, will get an M for Modified flag associated with them, <em>tax_id</em>
// and <em>favorite_book</em> are new fields, so they get an A flag for Added,
// and <em>dateofbirth</em> was deleted via unset(), and thus, gets a D flag for deleted.
$customer->write(); // Assume the latest revision is now 18.
 
// Load up customer ID #10 at revision 17
$customer->load(10, 17);
 
echo $customer->lastname; // echo's the value previously stored before Fisher was set as the lastname.
echo $customer->favorite_book; // echo's nothing, the field hasn't been created yet.
echo $customer->dateofbirth; // echo's December 18, 1982 for example

With each write() call, a new revision is created with the changes to the data. The Customer class makes use of an Entity-Attribute Value model. The fields associated with the Customer object are not stored as columns in the database. Instead, the fields are only stored historically with the specific customer. However, you can enforce a Customer to have a default set of fields. Each field must have a type, which can be as generic as “text” or as complex as “email”. More complex fields can have a regular expression and a hook function they must match in order to have their values set.

$customer->email_address = "vmc@leftnode.com"; // email_address is a specific field type, and thus, must pass a regex
$customer->email_address = "vmc"; // Doesn't match, value won't be set.

Versionable objects also have the ability to be cloned (similar to copied in Subversion). Thus, if one object is created from another, the primary key (in this case, the customer_id) is copied as the parent_id of the second object.

// Copies all of $customer at whatever revision it's
// loaded at with $customer2's parent_id as the id of $customer
$customer2 = clone $customer;
$customer2->write();

Speed and Efficiency

The first question asked, is, “Isn’t this very slow?” Fortunately, the answer is No, it’s surprisingly quick. In several initial load tests, a random object with 4000 revisions each with 0-20 fields updated per revision could have an arbitrary revision loaded in about 0.003 seconds. Of course, it is slower than using a database with a `customer` table having several columns, but it much, much more flexible. Again, it’s similar to normal source revision control: an overhead exists but at a nice feature improvement.

Conclusion

At first, especially for a Customer object, it may seem like overkill. However, there are times where historical information is necessary or even required. For example, in several industries, software must keep track of every change made to a piece of data (the banking industry is one such). It would be nice to build a system that stores historical data automatically.

The usefulness of this extends past just a basic Customer object. One could easily build an object for storing Wiki documents. With each write, the historical data is stored, and you could easily revert back to a previous version if necessary.

It is my hope that the new version of Artisan System will have some incredibly useful features that programmers can take advantage of. I’m particularly excited about versionable objects, and I look forward to hearing if its a good idea or not, and how it can be improved if so.

PS. I just know someone is going to let me know that Django or Rails has had functionality like this for several years.

History and Name of Artisan System

Posted by Vic Cherubini on December 01, 2009

This is a valid article, and is considered technically accurate up to Feb. 21, 2010

Artisan System has been in development for about a year and has gone through two distinct rewrites from scratch. The rewrites were as the result of underestimating the complexity of a framework. The version released today has been in development for 6 months. Development has been slow, but deliberate. Artisan System was written to be fast, small, and with an emphasis on good PHP coding standards.

Where did the name come from? Why Artisan System? In it’s first revision, the framework was named Artisan. Clearly, an Artisan is a master of their craft, and we envision PHP programmers using Artisan System as a tool to perfect their craft. After the initial versions of Artisan were written, they were named simply Artisan. Because it severely lacked a lot of features, development on this version began. The framework was renamed to Artisan System because it is meant to be used as system level libraries for web applications. In the end, a group of applications will be written with the name Artisan and they will use the Artisan System framework for their underlying structure.

Finally, we want to improve the image of PHP and PHP Programmers. Yes, there are a lot of very poorly written PHP software for myriad of reasons. However, we feel that great software can be written in PHP and we want Artisan System to prove that.

Questions, comments, and help offers can be redirected to vmc@leftnode.com

Artisan System Framework License

Posted by Vic Cherubini on December 01, 2009

This is a valid article, and is considered technically accurate up to Feb. 21, 2010

This software is provided ‘as-is’, without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  3. This notice may not be removed or altered from any source distribution.

Introducing the Artisan System SDK 2

Posted by Vic Cherubini on October 07, 2009

While the content of this article is accurate, the Git repository is no long valid as of Feb. 21, 2010

I released the Artisan System Framework in November 2008. I was very excited when it released, got some good feedback, got some bad feedback, but was very happy with my work. It went through about 8 months of development, and was rewritten twice. Ultimately I derived a lot of pleasure from releasing my first open source product.

With the 0.4 release coming in the next week, I felt it was appropriate to launch the SDK, or software development kit, so developers can become quickly acclimated with how the framework operates. The feedback I received from explaining how the Model-View Controller works in Artisan System was that it wasn’t as intuitive as I had thought. Rather than updating the post, I decided the best way to show its intuitiveness would be to release the SDK.

Because Leftnode is moving to git for some projects, I decided to release the SDK on github.com. You can find it at http://github.com/leftnode/artisan-sdk. It includes version 0.3beta of Artisan System, but will be upgraded to 0.4 when it is released.

The default SDK includes all of the code necessary to build a small website. It includes database access (for the contact form mail page), the Model-View Controller, and a global static class for passing objects between each other.

Installation is very simple.

  • Clone the repository in a web-serveable directory
  • Create a new MySQL database named `artisan` and run the artisan.sql file against it.
  • Copy configure.template.php to configure.php
  • Open configure.php in your editor
  • On a development server, set DEBUG_MODE to 1, on a live server, set it to 0.
  • Set the value for the DIR_ROOT define for the root location. Essentially, this is the directory where index.php resides.
  • Set the keys server, username, password, and database in the $config_artisan_db variable to your appropriate database settings.
  • Set the values of site_root and site_root_secure in the $config_artisan_router variable.
  • If your web server has mod_rewrite (or similar) enabled, keep rewrite in $config_artisan_router as true, otherwise, set it to false.
  • Set the email_list value in $config_form to an array of email addresses the form should submit to.

This concludes the installation. Currently, it is done manually, but an automatic installation will be available in the future.

To access the initial site, if you have http://localhost/ set up properly, you can go to http://localhost/directory/ where directory is the name of the directory you placed all of the files in.

After you’ve verified the installation worked properly, and navigated through the small website, we’ll discuss the overall architecture of the SDK.

Application Directory Structure

The first directory you should pay attention to is app/. Open it, and you’ll see two sub-directories, Page/ and Root/. In Root/, you will see one PHP file, Root.php and a directory, View/. Opening Root.php shows a small class file.

<?php
 
class Root_Controller extends Artisan_Controller {
  protected $_layout = 'index';
 
  public function renderLayout($view) {
    $this->view->css_artisan = DIR_CSS . 'artisan.css';
 
    $this->render('root/header', 'header');
    $this->render('root/menu', 'menu');
 
    $this->render($view, 'body');
 
    $this->render('root/footer', 'footer');
  }
 
  protected function _redirect($url) {
    header("Location: " . $url);
    exit;
  }
}

This is the root Controller class. All Controllers in Artisan System must extend from the class Artisan_Controller. Because this Root_Controller extends Artisan_Controller, all subsequent Controllers will extend it. All Controllers must also be named {Name}_Controller, where {Name} is the actual name of the Controller.

All Controllers reside in a central directory, with sub-directories corresponding to each Controller.

app/
  Root/
    Root.php
    View/
      header.phtml
      footer.phtml
  Index/
    Index.php
    Model/
      Index.php
    View/
      index.phtml
      alternate.phtml
  Account
    Account.php
    Model/
      Account.php
    View/
      account.phtml
      update.phtml
      friends.phtml
      contacts.phtml
  Profile
    Profile.php
    Model/
      Profile.php
    View/
      profile.phtml

With this structure, any Controller can load a View of any other Controller. Additionally, the file in the Model/ directory handles the validation rules for different sections of each Controller.

Rendering Views in a Controller is easy with the render() method. It takes two optional paramters, $view_file and $content_block. $view_file defaults to the name of the method you’re calling with the URL (see URL Routing below), and $content_block defaults to no content block, meaning the view is rendered directly to the output stream.

By passing a full path for the $view_file parameter in render(), it will load up that View file within that Controller directory. If no path is passed, the View file from that Controller directory is loaded.

Because an application does not know of the concept of a header or footer (or other repeated content on the page), the Root_Controller was added. Each subsequent Controller extends Root_Controller, and every method in that Controller would call $this->renderLayout() rather than render() directly. As a result, the header, menu, and footer Views are always loaded in. Without this, one would have to load in each of these at every method. Backing up a directory and opening to Page/Page.php shows how this works.

<?php
 
require_once 'app/Root/Root.php';
 
class Page_Controller extends Root_Controller {
  // ##### POST Methods ##### //
 
  public function contactPost() {
    $form_id = intval($this->getParam('form_id'));
    $contact = $this->getParam('contact');
 
    try {
      $contactor = Artisan::getContactor();
      $contactor->setFormId($form_id)->setFieldList($contact)->send();
 
      $this->contactGet();
    } catch ( Artisan_Exception $e ) {
      // Determine what to do...
    }
  }
 
  // ##### GET Methods ##### //
 
  public function indexGet() {
    $this->renderLayout('index');
  }
 
  public function contactGet() {
    $this->renderLayout('contact');
  }
 
  public function aboutusGet() {
    $this->renderLayout('aboutus');
  }
 
  public function servicesGet() {
    $this->renderLayout('services');
  }
}

Because Page_Controller extends Root_Controller, it can call renderLayout() with the name of the View to load. Focusing on the *Get() methods for now, you see how simple they are. The method indexGet() loads up the index.phtml View, which is found in app/Page/View/.

Library Files

In the lib/ directory, you’ll see on sub-directory, Artisan/ and two PHP files. The Artisan/ sub-directory contains the entire Artisan System framework. Artisan.php is a static class that serves as a simple entry point into the system. Most of the methods within here could be combined into a single chunk of code in index.php, however, by putting them in separate static methods in a single class, they can be loaded in different areas of an application, making deployment easy and avoiding globalizing variables. Finally, Contactor.php is a simple class for managing a Contact Us form.

URL Routing

Controllers are broken into different methods that are accessible through the URL. With mod_rewrite turned on, URL’s look like: http://website.com/controller/method/arg1/arg2/argN. The first value after the base URL is the name of the Controller to load. Next, is the method within that Controller. Finally, any additional values, separated by forward slashes, are passed in as arguments to the method. Which method is called in the Controller is determined by the request type. GET requests route to methodGet(), and POST requests route to methodPost(). Thus, going to http://website.com/account/update would attempt to load Account_Controller::updateGet(), while posting a form to that same URL would attempt to load Account_Controller::updatePost().

Public Facing Files

Navigating to the root directory and then to public/ shows several sub-directories: css/, image/, layout/, and locale/. The names should be relatively intuitive as to what they do. One note: layout/ holds the different layout files. Layout files are what are loaded automatically after a view is rendered if the $_layout property of the Artisan_Controller class is defined. Because it is defined as ‘index’ in the code above, the index.phtml file is loaded. This small file is parsed by the Controller itself, with each content block being rendered to the appropriate area.

Download

You can download the initial release of the Artisan System SDK using Git from github.com. The public clone URL is git://github.com/leftnode/artisan-sdk.git

Model-View Controller in Artisan System 1

Posted by Vic Cherubini on October 02, 2009

This is a valid article, and is considered technically accurate up to Feb. 21, 2010

When Artisan System was first started, I had a vague idea of what the Model-View Controller pattern (MVC) was. As a result, the initial Artisan System framework had a hacked together inefficient MVC layout. It was burdensome and unintuitive. After researching more as to what MVC really is, I rewrote it from scratch. Twice. Now, the latest version of Artisan System, 0.4, has a complete MVC engine that’s efficient and very easy to use.

Models, Views, and Controllers

Finding an easy to understand idea of what MVC is was hard to do. Most contained the original layout of the idea proposed by Xerox in the 1970’s. The idea has changed since then, especially for web development. The overall idea of MVC is to separate business logic (what is done with the data) with the display logic (how the data is viewed).

Your model is your data. It can come from anywhere: flat files, XML, a database, a key/value store. The view is what determines how the data will be displayed. Views can generally have some logic in them, but it should be entirely confined to displaying data. A simple example would be to display a different greeting depending on a user type.

<?php if ( $user->type == USER_TYPE_BUSINESS ): ?>
  <?php echo _('Welcome to the website, Business User.'); ?>
<?php else: ?>
  <?php echo _('Welcome to the website, Consumer User.'); ?>
<?php endif; ?>

The Controller determines what to do with the data sent to it, how it affects the Model, and how to render the data in the View. When broken into their individual terms, understanding the MVC pattern becomes quite clear.

Artisan System contains a series of mostly abstract classes to help define each sub-section of MVC. An abstract Artisan_Controller class is meant to be extended for each of a websites controllers. Each controller has an Artisan_View object as a member. This object is what is responsible for rendering one or more views associated with a Controller. Finally, each Controller has an extended Artisan_Model object that defines validation rules for any forms associated with that View. Generally, each view should have a single form, if any, but multiple forms per View are easily supported.

On the filesystem, this is laid out intuitively as well.

application/
  Root/
    View/
      header.phtml
      menu.phtml
      footer.phtml
    Root.php
  Index/
    Model/
      Index.php
    View/
      about.phtml
      index.phtml
    Index.php

The main files in each sub directory are the Controller files, the file in the Model directory is the Model validation file, and all of the files in the View directory correspond to a View. Because they are .phtml files, the views themselves can contain PHP code. The alternative PHP syntax should be used for them, as it is a built in templating language and much more suited for integration with HTML.

Routing and Redirection

As of this writing, the Controllers are URL based. This means the URL specifies which Controller and View to load. In a typical Artisan System application, the index.php file is very small and handles this.

<?php
 
require_once 'Artisan/Controller/Router.php';
 
$config_artisan_router = new Artisan_Config_Array(array(
  'site_root' => 'http://www.example.com',
  'site_root_secure' => 'https://www.example.com/',
  'root_dir' => 'application',
  'layout_dir' => 'layout',
  'default_controller' => 'Index',
  'default_method' => 'index',
  'default_layout' => 'index',
  'rewrite' => true
  )
);
 
$artisanRouter = new Artisan_Controller_Router($config_artisan_router);
echo $artisanRouter->dispatch();
 
exit;

Basic URL’s without using any rewrite’s are in the form: index.php?u=controller/view/arg1/arg2/argN

Thus, if the $_REQUEST variable u is used for anything, the application will not work. In this example, the value passed to u is exploded based on the slashes. The first value is the name of the Controller to load, the next is the name of the method within that controller to load. Any values after the frist two are passed in as arguments to that method.

Thus, the URL index.php?u=profile/update/1 called through a POST request will cause the following actions to occur.

  1. Profile/Profile.php is loaded
  2. Profile_Controller::updatePost() is found
  3. Profile_Controller::updatePost(1) is called (albeit, not statically)

If the request was made by GET, the method updateGet() would be used instead.

If the method is not found, an exception is thrown, which can be handled by the router.

Because each Controller extends the base Artisan_Controller class, they can easily render the view associated with that Controller. By default, the Controller will attempt to render a view of the same name as the Controller, however, its generally best to specify one.

<?php
 
class Index_Controller extends Artisan_Controller {
  public function indexGet($page) {
    $page_data = load_page_data($page);
    $this->page_data = $page_data;
    $this->render('index');
 
    return true;
  }
 
  public function updatePost($page) {
    $data = $this->getInput('page');
    update_page_data($page, $data);
 
    $this->redirect('index');
  }
}

The above code is generic in nature, and obviously the methods load_page_data() and update_page_data() need to be defined, but it gives a general layout for a controller.

In future revisions, the routing will remain URL based by default, but can easily be overwritten with a rewrite table.

By default, the controller will render that data directly to the browser. This is useful for simple AJAX requests where one simply wants basic HTML, JSON, or XML returned. However, on non-AJAX requests, the full HTML page needs to be rendered. Artisan System makes use of Layouts and Content Blocks to facilitate this.

Layouts and Content Blocks

Artisan System uses a layout file to handle the final layout of a page. The layout file is mainly intended for designers to be able to re-theme an application easily.

Layout files are .phtml files as well, but live in a directory named layout (by default). Each has a unique name and is referenced by the Controller calling it. Thus, each Controller could have a different layout, although its generally not necessary.

The root Artisan_Controller class defines a protected member variable $_layout. The value of this variable is the name of the layout file, minus the extension, to be loaded. Additionally, a method, public Artisan_Controller::setLayout($layout) is available to set the layout without having to reference the variable directly. By default, no layout is set, and thus each view is rendered directly to the browser. However, the render() method of the Artisan_Controller class takes an optional second parameter, the name of the content block to render to. After the view is rendered to a specific content block, that block can be loaded in the layout (or another view).

<?php
 
class Index_Controller extends Artisan_Controller {
  protected $_layout = 'default';
 
  public function indexGet() {
    // $title is now a variable that can be used directly in the view.
    $this->title = _('Welcome to my site!');
 
    // Renders the index.phtml view to the 'body' content block.
    $this->render('index', 'body');
    return true;
  }
}

The index.phtml view is found in application/Index/View/ and is very straightforward.

<?php echo $title; ?>
 
<p>Thank you for taking the time to read my website.</p>

However, because this method renders to a specific content block, body, nothing will be displayed until the appropriate layout is loaded. The loading and rendering of the layout file happens automatically by the Artisan_Controller file in the load() method.

The layout file, default.phtml is located in public/layout and is equally as straightforward.

<!doctype html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <title>Welcome to my Site!</title>
</head>
<body>
 
<?php echo $this->getBlock('body'); ?>
 
</body>
</html>

The default.phtml layout file now loads the body content block and the resulting concatenation of both is rendered to the browser.

Conclusion

Separation of content from design from logic was always a difficult design decision to make. However, with Artisan System, this issue is effortless and intuitive.