Omeka: A Web-based Publishing System

omeka_1238110767043

The Center for History and New Media has released an open source version of their Web-based publishing system built on top of the Zend Framework.

Omeka is a Web-based publishing platform for scholars, librarians, archivists, museum professionals, educators, and cultural enthusiasts. Its “five-minute setup” makes launching an online exhibition as easy as launching a blog. Omeka is designed with non-IT specialists in mind, allowing users to focus on content and interpretation rather than programming. It brings Web 2.0 technologies and approaches to academic and cultural websites to foster user interaction and participation. It makes top-shelf design easy with a simple and flexible templating system. Its robust open-source developer and user communities underwrite Omeka’s stability and sustainability.

Thank you guys for open sourcing this great application!

Links

Domain-Driven Design: Sample Application

Last updated: 15 Feb, 2010

Part 1: Domain-Driven Design and MVC Architectures
Part 2: Domain-Driven Design: Data Access Strategies
Part 3: Domain-Driven Design: The Repository

Some of the Domain-driven design concepts explained above are applied in this sample application.

Directory Structure

app/
    config/
    controllers/
        UserController.php
    domain/
        entities/
            User.php
            UserProfile.php
        repositories/
            UserRepository.php
    views/
lib/
public/

The domain layer should be well separated from the other layers and it should have few dependencies on the framework you are using.

User Entity

The User and UserProfile objects have a one-to-one relationship and form an Aggregate. An Aggregate is as a collection of related objects that have references between each other. Within an Aggregate there’s always an Aggregate Root (parent Entity), in this case User:

class User
{
    private $id;
    private $name;

    /* @var UserProfile */
    private $profile;

    public function __construct($id, $name)
    {
        $this->id = $id;
        $this->name = $name;
    }

    public function setProfile(UserProfile $profile)
    {
        $this->profile = $profile;
    }

    public function getProfile()
    {
        return $this->profile;
    }
}

class UserProfile
{
    private $id;

    public function __construct($id)
    {
        $this->id = $id;
    }
}

Users Collection

A collection is simply an object that groups multiple elements into a single unit.

class Users
{
    private $elements = array();

    public function __construct(array $users)
    {
        foreach ($users as $user) {
            if (!($user instanceof User)) {
                throw new Exception();
            }
            $this->elements[] = $user;
        }
    }

    public function toArray()
    {
        return $this->elements;
    }
}

User DAO

The UserDAO class allows data access mechanisms to change independently of the code that uses the data:

interface UserDao
{
    public function find($id);
    public function findAll();
}

class UserDatabaseDao implements UserDao
{
    public function find($id)
    {
        $dataSource = Zf_Orm_Manager::getInstance()->getDataSource()
        $db = $dataSource->getConnection('slave');
        $query = $db->select()->from('user')->where('id = ?', $id);
        return $db->fetchRow($query);
    }

    public function findAll()
    {
        ...
        return $db->fetchAll($query);
    }
}

interface UserProfileDao
{
    public function find($id);
    public function findByUserId($id);
}

class UserProfileDatabaseDao implements UserProfileDao
{
    public function find($id)
    {
        ...
    }

    public function findByUserId($id)
    {
        $dataSource = Zf_Orm_Manager::getInstance()->getDataSource()
        $db = $dataSource->getConnection('slave');
        $query = $db->select()->from('user_profile')->where('user_id = ?', $id);
        return $db->fetchRow($query);
    }
}

User Repository

A Repository is basically a collection of Aggregate Roots. Collections are used to store, retrieve and manipulate Entities and Value objects, however, object management is beyond the scope of this post. The Repository object can inject dependencies on demand, making the instantiation process inexpensive.

class UserRepository
{
    /* @var UserDatabaseDao */
    private $userDao;

    /* @var UserProfileDatabaseDao */
    private $userProfileDao;

    public function __construct()
    {
    	$this->userDao = new UserDatabaseDao();
    	$this->userProfileDao = new UserProfileDatabaseDao();
    }

    public function find($id)
    {
        $row = $this->userDao->find($id);
        $user = new User($row['id'], $row['name']);

        $row = $this->userProfileDao->findByUserId($id);
        if (isset($row['id'])) {
            $profile = new UserProfile($row['id']);
            $user->setProfile($profile);
        }

        return $user;
    }

    public function findAll()
    {
        $users = array();
        $rows = $this->userDao->findAll();
        foreach ($rows as $row) {
            $users[] = new User($row['id'], $row['name']);
        }
        return new Users($users);
    }
}

Usage:

$repository = new UserRepository();
$user = $repository->find(1);
$profile = $user->getProfile();
$users = $repository->findAll();

Source Code

http://svn.fedecarg.com/repo/Zf/Orm

Links

If you’re interested in learning more about Domain-driven design, I recommend the following articles:

Domain Driven Design and Development In Practice
Domain-Driven Design in an Evolving Architecture

Domain-Driven Design: The Repository

Part 2: Domain-Driven Design: Data Access Strategies

The Ubiquitous Language

The ubiquitous language is the foundation of Domain-driven design. The concept is simple, developers and domain experts share a common language that both understand. This language is set in business terminology, not technical terminology. This ubiquitous language allows the technical team become part of the business.

The Repository

Repositories play an important part in DDD, they speak the language of the domain and act as mediators between the domain and data mapping layers. They provide a common language to all team members by translating technical terminology into business terminology.

In a nutshell, a Repository:

  • Is not a data access layer
  • Provides a higher level of data manipulation
  • Is persistence ignorance
  • Is a collection of aggregate roots
  • Offers a mechanism to manage entities

Data Access Objects

In the absence of an ORM framework, the Data Access Object (DAO) handles the impedance mismatch that a relational database has with object-oriented techniques. In DDD, you inject Repositories, not DAO’s in domain entities. For example, imagine you have an entity named User that needs to access the database to retrieve the User details:

class User
{
    private $id;
    private $name;

    public function __construct(UserDao $dao, $id)
    {
        $row = $dao->find($id);
        $this->setId($row['id']);
        $this->setName($row['name']);
    }

    public function setId($id) {}
    public function getId() {}
    public function setName($name) {}
    public function getName() {}
}

The User DAO class will look something like this:

interface UserDao
{
    public function fetchRow($id);
}

class UserDatabaseDaoImpl implements UserDao
{
    public function fetchRow($id)
    {
        ...
        $query = $db->select();
        $query->from('user');
        $query->where('id = ?', $id);
        return $db->fetchRow($query);
    }
}

$dao = new UserDatabaseDaoImpl();
$user = new User($dao, 1);
$userId = $user->getId();

But, what about separation of concerns? DAO’s are related to persistence, and persistence is infrastructure, not domain. The main problem with the example above is that we have lots of different concerns polluting the domain. According to DDD, an object should be distilled until nothing remains that does not relate to its meaning or support its role in interactions. And that’s exactly the problem the Repository pattern tries to solve.

Injecting Repositories

Lets create a UserRepository class to isolate the domain object from details of the UserDatabaseDaoImpl class:

class User
{
    private $id;
    private $name;

    public function __construct(UserRepository $repository, $id)
    {
        $row = $repository->find($id);
        $this->setId($row['id']);
        $this->setName($row['name']);
    }

    public function setId($id) {}
    public function getId() {}
    public function setName($name) {}
    public function getName() {}
}

It’s the responsibility of the UserRepository to work with all necessary DAO’s and provide all data access services to the domain model in the language which the domain understands.

interface UserRepository
{
    public function find($id);
}

class UserRepositoryImpl implements UserRepository
{
    private $databaseDao;

    public function setDatabaseDao(UserDao $dao) {}
    public function getDatabaseDao() {}

    public function find($id)
    {
        return $this->getDatabaseDao()->find($id);

    }
}

$userRepository = new UserRepositoryImpl();
$userRepository->setDatabaseDao(new UserDatabaseDaoImpl());

$user = new User($userRepository, 1);
$userId = $user->getId();
$userName = $user->getName();

The main difference between the Repository and the DAO is that the DAO is at a lower level of abstraction and doesn’t speak the ubiquitous language of the domain.

So, what’s next?

The process of creating an entity is complex, because an entity always has relationship with other objects in your domain model. When creating an entity, we have to initialize its relationships as well. Therefore, it’s a good practice to delegate this task to another object.

We’ve seen how to write a persistence-ignorant domain model. Next, I’ll explain how to automate the creation and injection of dependencies.

Part 4: Domain-Driven Design: Sample Application

Domain-Driven Design: Data Access Strategies

Part 1: Domain-Driven Design and MVC Architectures

The Domain Model

Here are some of the features a Domain-driven design framework should support:

  • A domain model that is independent and decoupled from the application.
  • A reusable library that can be used in many different domain-specific applications.
  • Dependency Injection in order to inject Repositories and Services into Domain Objects.
  • Integration with unit testing frameworks, such as PHPUnit.
  • Good integration with other frameworks, such as Zend, Symfony, Doctrine, etc.

The Zend Framework, for example, is part of the infrastructure layer and acts as a supporting library for all the other layers. However, the domain layer should be well isolated from the other layers of the application and should not be dependent on the framework you are using.

Data Access Strategies

When accessing data from a data source, you have to decide how your application will communicate with a data source. Each data access strategy has its own advantages and disadvantages. Here are some design patterns that support DDD:

Generic DAO’s

Data Access Objects (DAO’s) and Repositories play an important role in DDD. The goal of a DAO is to abstract and encapsulate all access to the data and provide an interface. The DAO always connects, reads and saves data to a data source. From the applications point of view, it makes no difference when it accesses a database, XML file or Web service:

$user = new UserDbDao();
$row = $user->findUserById(456);
echo $row->name;

$user = new UserXmlDao();
$row = $user->findUserById(456);
echo $row->name;

Table Data Gateway

An object that acts as a Gateway to a database table. One instance handles all the rows in the table. The Zend_Db_Table solution is an implementation of the Table Data Gateway pattern:

$user = new User();
$rows = $user->find(456);
$row = $rows->current();
echo $row->name;

More info: Table Data Gateway

Row Data Gateway

An object that acts as a Gateway to a single record in a data source. There is one instance per row. Zend_Db_Table_Row is an implementation of the Row Data Gateway pattern:

$user = new User();
$row = $user->fetchRow($user->select()->where('user_id = ?', 1));
echo $row->name;

More info: Row Data Gateway

Active Record

An object that wraps a row in a database table or view, encapsulates the database access, and adds domain logic on that data. The Mad_Model component is an  ORM layer that follows the Active Record pattern where tables map to classes, rows map to objects, and columns to object attributes:

$user = new User();
$userFinder = new UserFinder();
$row = $userFinder->find(456);

More info: Active Record

Data Mapper

A layer of Mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself:

$user = new User();
$userMapper = new UserMapper();
$row = $userMapper->findByEmail($email);

More info: Data Mapper

Data Transfer Objects

A Data Transfer Object (DTO) in Domain-driven design is not the same as a Value Object. A DTO is often used in combination with a DAO to encapsulate data. It allows you to reduce communication effort when dealing with a lot of small data entities. For example:

class UserData
{
    public function setId($id) {}
    public function getId() {}
    public function setFirstName($firstName) {}
    public function getFirstName() {}
    public function setLastName($lastName) {}
    public function getLastName() {}
}

$user = new UserData();
$user->setFirstName('Jim');
$user->setLastName('Morrison');

$userDao = new UserDbDao();
$userDao->insert($user);

A DTO is a simple container for a set of aggregated data. It should contain no business logic and limit its behaviour to activities such as internal consistency checking and basic validation. Be careful not to make the DTO depend on any new classes as a result of implementing these methods.

Part 3: Domain-Driven Design: The Repository

Domain-Driven Design and MVC Architectures

According to Eric Evans, Domain-driven design (DDD) is not a technology or a methodology. It’s a different way of thinking about how to organize your applications and structure your code. This way of thinking complements very well the popular MVC architecture. The domain model provides a structural view of the system. Most of the time, applications don’t change, what changes is the domain. MVC, however, doesn’t really tell you how your model should be structured. That’s why some frameworks don’t force you to use a specific model structure, instead, they let your model evolve as your knowledge and expertise grows.

Domain-driven design separates the model layer “M” of MVC into an application, domain and infrastructure layer. The infrastructure layer is used to retrieve and store data. The domain layer is where the business knowledge or expertise is. The application layer is responsible for coordinating the infrastructure and domain layers to make a useful application. Typically, it would use the infrastructure to obtain the data, consult the domain to see what should be done, and then use the infrastructure again to achieve the results. Srini Penchikala explains this in more detail here: “Domain Driven Design and Development In Practice“.

Object-oriented programming is the most important element in the domain implementation. Domain objects are designed using classes and interfaces, and take advantage of OOP concepts like inheritance, encapsulation, and polymorphism. Most of the domain elements are true objects with both State (attributes) and Behaviour (methods or operations that act on the state). Entities and Value Objects in DDD are classic examples of OOP concepts since they have both state and behaviour.

Terminology used by Domain-driven design

  • Entity: An object which has a distinct identity. For example, a User entity has a distinct identity with an ID.
  • Value Object: An object which has no distinct identity, like numbers and dates. For example, if two Users have the same date of birth, you can have multiple copies of an object that represents the date 16 Jan 1982.
  • Factory: Used to create Entities. For example, you can use a Factory to create a Profile entity from a User entity.
  • Repository: Used to store, retrieve and delete domain objects from different storage implementations. For example, you can use a Repository to store the Profile your Factory created.
  • Service: When an operation does not conceptually belong to any object.

The purpose of this post was to provide a brief introduction to Domain-driven design.

Part 2: Domain-Driven Design: Data Access Strategies

Links

If you’re interested in learning more about Domain-driven design or Model-driven design, I recommend the following articles:

Zend Framework: The Cost of Flexibility is Complexity

The Zend Framework is a very flexible system, in fact, it can be used to build practically anything. But, the problem with using a flexible system is that flexibility costs. And the cost of flexibility is complexity.

Martin Fowler wrote:

Every time you put extra stuff into your code to make it more flexible, you are usually adding more complexity. If your guess about the flexibility needs of your software is correct, then you are ahead of the game. You’ve gained. But if you get it wrong, you’ve only added complexity that makes it more difficult to change your software.

Don’t assume that just because you’re using an object-oriented framework you are writing reusable and maintainable code. You are just structuring your spaghetti code. As Paul Graham put it: “Object-oriented programming offers a sustainable way to write spaghetti code”. The main problem with flexibility is that most developers give up trying to understand. I don’t blame them, no one likes dealing with complexity. However, flexibility is sometimes required and generally always desirable. But, sometimes we forget that frameworks exist to help us solve or address complex issues, not to fix bad design decisions for us. So if your code is difficult to understand or unit test, then you are probably doing something wrong.

Just because you can, doesn’t mean you should

What’s the best way to render a view script in the Zend Framework? Think, don’t give up yet. Is it enabling or disabling the ViewRenderer action helper? Remember, the framework allows you to shape the Zend_Controller_Action class to your application’s needs.

The manual clearly states that:

By default, the front controller enables the ViewRenderer action helper. This helper takes care of injecting the view object into the controller, as well as automatically rendering views.

However, no one stops you from doing it manually:

Zend_Controller_Action provides a rudimentary and flexible mechanism for view integration. Two methods accomplish this, initView() and render(); the former method lazy-loads the $view public property, and the latter renders a view based on the current requested action, using the directory hierarchy to determine the script path.

Developer A

class IndexController extends Zend_Controller_Action
{
    public function searchAction()
    {
        $query = $this->_getParam('q', null);
        if (null === $query) {
            $this->view->error = 'Invalid query';
            return;
        }

        $this->view->query = $query;
        if (is_numeric($query)) {
            $this->setUserDetailsById($query);
        } else {
            $this->setUserDetailsByName($query);
        }
    }

    public function setUserDetailsByName($name)
    {
        $row = $this->findUserByName($name);
        $this->view->userId = $row['id'];
        $this->view->userName = $row['name'];
    }

    public function setUserDetailsById($id)
    {
        $row = $this->findUserById($id);
        $this->view->userId = $row['id'];
        $this->view->userName = $row['name'];
    }
}

Developer B

class IndexController extends Zend_Controller_Action
{
    protected $_viewParams = array(
        'error'    => null,
        'query'    => null,
        'userId'   => null,
        'userName' => null,
    );

    public function init()
    {
        $this->_helper->removeHelper('viewRenderer');
    }

    public function searchAction()
    {
        $query = $this->_getParam('q', null);
        if (null === $query) {
            $this->_viewParams['error'] = 'Invalid query';
            $this->renderView('search');
            return false;
        }

        return $this->displayUserDetails($query);
    }

    public function displayUserDetails($query)
    {
        if (is_numeric($query)) {
            $row = $this->getUserDetailsById($query);
        } else {
            $row = $this->getUserDetailsByName($query);
        }

        if (!$row) {
            $this->_viewParams['error'] = 'User not found';
            $this->renderView('search');
            return false;
        }

        foreach ($this->_viewParams as $key => $value) {
            if (!array_key_exists($key, $row) {
                continue;
            }
            $this->_viewParams[$key] = $row[$key];
        }

        $this->_viewParams['query'] = $query;
        $this->renderView('search');

        return true;
    }

    public function renderView($template)
    {
        $view = $this->initView();
        foreach ($this->_viewParams as $key => $value) {
            $view->$key = $value;
        }
        $this->render($template);
    }

    public function getUserDetailsByName($name)
    {
        return $this->findUserByName($name);
    }

    public function getUserDetailsById($id)
    {
        return $this->findUserById($id);
    }
}

Same problem, different solutions.

Now, guess who is doing test-driven development, has all his code unit tested, puts commonly used code into libraries, abstracts out common patterns of behaviour, writes his code using the top-down fashion and uses the principle of “least astonishment”.

Developer A or B?

Conclusion

Many requirements lie in the future and are unknowable at the time our application is designed and built. To avoid burdensome maintenance costs developers must therefore rely on a system’s ability to change gracefully its flexibility. The combination of flexibility and smart design can reduce the maintenance burden. It’s up to us, the developers, to change our thinking when using a flexible framework. Like I said before, frameworks exist to help us solve complex issues, not to make decisions for us.

Apache Log Analyzer 2 Feed

I found this project thanks to Raphael’s post Turning a Zend_Log log file into an RSS feed.

Developed by Simone Carletti, ApacheLogAnalyzer2Feed is a really powerful open source PHP 5 class to parse and analyse Apache Web Server log files. Results are converted into a feed to let users subscribe them with a feed reader. You can define custom filters based on logs data — for instance User-Agent, IP, requested page, etc— and combine them to select just a limited resultset. The class can easily be extended with additional filters and custom feed handlers.

On a side note, Simone’s Wiki is powered by Redmine, an awesome Ruby on Rails Wiki and project management system that’s worth checking out.