Developing a Simple Blog Application in PHP

In this third part of the series, I develop the domain layer of a sample blog application. In this case, for the sake of simplicity, the domain layer will be able to fetch, save, and delete blog post entries from the underlying storage layer.

If you frequently use an object-oriented approach to build your own PHP applications, you know that creating object graphs can be pretty challenging. After all, providing objects with their dependencies is not as easy as it seems, even in the simplest use case. Fortunately, things aren’t hopeless when it comes to joining sets of interconnected objects; in the last few years, several approaches implemented for a long time in more mature languages (especially Java) have found their way into PHP. 

The first of these approaches is dependency injection (DI), which is now widely utilized by well-trusted frameworks and libraries, such as the Zend Framework, Symfony and Doctrine (to name a few). However, there’s another method that you can use to give objects the collaborators they require to work properly. Yes, as you may have already guessed, in this case I’m talking about service locators. These are nothing but simple mediators whose responsibility it is to provide the objects with the corresponding dependencies, either statically or dynamically.

Since the most effective way to demonstrate the functionality of service locators is by example, in earlier tutorials of this series I developed some approachable ones that showed how to use a service locator in the development of a basic registry library. In the first case, the locator was consumed statically. This approach is more difficult to test. In the second case, the locator was injected through the constructor of a client class, thus demonstrating that DI and service locators aren’t mutually exclusive methods. They can live together in sweet harmony as well.

While utilizing a service locator in the implementation of a basic registry is all well and good, at least for didactic purposes, I’d like to show you how to use this approach in a more realistic case. In this and upcoming articles in the series, I’m going to create a simple, yet functional blog application, which will use a locator to create its object graphs.

If this proposal doesn’t whet your appetite for knowledge, I’m going to astonish you with three different versions of the blog. The first one will rely purely on dependency injection, the second one will make use of a static locator, and the last one will combine the two previous approaches, by employing an injected locator.

Now it’s time to leave the dull theory behind and start learning how to use a service locator in the construction of a blogging program. Let’s get going!

Lazy-loading source classes: creating a simple autoloader

Since the construction of the blog application mentioned in the introduction will make use of a bunch of classes, the first step is to define an autoloader. This autoloader will lazy-load the pertinent classes (and eventually a couple of interfaces) without having to appeal to multiple PHP requires.

With that said, the autoloader looks like this: 

(Autoloader.php)

<?php

class Autoloader
{
    private static $_instance;
   
    /**
     * Get the Singleton instance of the autoloader
     */
    public static function getInstance()
    {
        if (self::$_instance === null) {
            self::$_instance = new self;
        }
        return self::$_instance;
    } 
   
    /**
     * Reset the instance of the autoloader
     */
    public static function resetInstance()
    {
        self::$_instance = null;
    }
   
    /**
     * Class constructor
     */
    private function __construct()
    {
        spl_autoload_register(array(__CLASS__, ‘load’));
    }
   
    /**
     * Prevent to clone the instance of the autoloader
     */
    private function __clone(){}
   
    /**
     * Load a given class or interface
     */
    public static function load($class)
    {
        $file = str_replace(”, ‘/’, $class) . ‘.php';
        if (!file_exists($file)) {
            throw new AutoloaderException(‘The file ‘ . $file . ‘ containing the requested class or interface ‘ . $class . ‘ was not found.’);
        }
        require $file;
        if (!class_exists($class, false) && !interface_exists($class, false)) {
            throw new AutoloaderException(‘The requested class or interface ‘ . $class . ‘ was not found.’);
        }
    }  
}

 

(AutoloaderException.php)

<?php

class AutoloaderException extends Exception{}

Well, if you’ve read some of my other articles published lately here at the Developer Shed network, you’ll find the implementation of the above autoloader very familiar. In simple terms, this class is a Singleton that includes name spaced classes and interfaces on demand by using the PHP SPL stack. That is all it does. 

Now that you’ve grasped how this autoloader functions, it’s time to start building the source classes that will make up the domain layer of this sample blog program. The first of these classes will be an abstract parent, and its definition will be shown in the upcoming section.

To see how this abstract class looks, jump ahead and read the lines to come.

{mospagebreak title=Defining generic entities for the domain layer}

In the real world, a blog application usually manages several entities and value objects. To keep things clear and understandable, however, in this case my blog application’s domain layer will be composed only of plain blog entries. Even though this schema is really primitive, it’s necessary first to create a class that models generic entities, and then one that specifically defines the data structure and constraints of the pertinent entries.

With that said, here’s the source code of the former. Check it out:  

(Blog/Entity/EntityAbstract.php)

<?php

namespace BlogEntity;

abstract class EntityAbstract
{
    protected $_values = array();
    protected $_allowedFields = array();
   
    /**
     * Class constructor
     */
    public function __construct(array $data)
    {
        foreach ($data as $name => $value) {
            $this->$name = $value;
        }
    }
   
    /**
     * Assign a value to the specified field via the corresponding mutator (if it exists);
     * otherwise, assign the value directly to the ‘$_values’ protected array
     */
    public function __set($name, $value)
    {  
        if (!in_array($name, $this->_allowedFields)) {
            throw new EntityException(‘The field ‘ . $name . ‘ is not allowed for this entity.’); 
        }
        $mutator = ‘set’ . ucfirst($name);
        if (method_exists($this, $mutator) && is_callable(array($this, $mutator))) {
            $this->$mutator($value);          
        }
        else {
            $this->_values[$name] = $value;
        }   
    }
   
    /**
     * Get the value assigned to the specified field via the corresponding getter (if it exists);
    otherwise, get the value directly from the ‘$_values’ protected array
     */
    public function __get($name)
    {
        if (!in_array($name, $this->_allowedFields)) {
            throw new EntityException(‘The field ‘ . $name . ‘ is not allowed for this entity.’);   
        }
        $accessor = ‘get’ . ucfirst($name);
        if (method_exists($this, $accessor) && is_callable(array($this, $accessor))) {
            return $this->$accessor;   
        }
        if (array_key_exists($name, $this->_values)) {
            return $this->_values[$name];
        }
        throw new EntityException(‘The field ‘ . $name . ‘ has not been set for this entity yet.’);
    }
   
    /**
     * Check if the specified field exists in the entity
     */  
    public function __isset($name)
    {
        return isset($this->_values[$name]);
    }
         
    /**
     * Unset the specified field from the entity
     */  
    public function __unset($name)
    {
        if (isset($name, $this->_values)) {
            unset($this->_values[$name]);
        }
    }
      
    /**
     * Get the values assigned to the fields of the entity
     */
    public function toArray()
    {
        return $this->_values;
    }             
}

 

(Blog/Entity/EntityException.php)

<?php

namespace BlogEntity;

class EntityException extends Exception {}

If you found it easy to grasp the underlying logic of the autoloader, you should feel the same way about the “EntityAbstract” class above, since I’ve used it previously in other Dev Shed tutorials as well. Nevertheless, if you’re not familiar with the operations that this class performs, don’t worry; they’re very simple to follow. This class uses the “__set()” and “__get()” PHP magic methods to assign and retrieve, via the corresponding mutators/getters (when possible), the values of the fields of an entity. The $_allowedFields property controls which fields are allowable for a particular entity, which makes it easy to define specific constraints for certain types of domain objects.

With this abstract parent laid down comfortably on top of the hierarchy, it’s really simple to create a refined implementation of it to model blog post entries. Given that, in the next section I’m going to spawn a subclass from the parent, which will define the metadata and constraints that will be applied to the  blog entries.

To see how this subclass will look, keep reading.

Going one step further: modeling blog post entities

As I just explained, creating a class that specifically models blog post entries is a straightforward process. In fact, it’s reduced to subclassing the previous abstract parent and implementing (optionally) the corresponding mutators/getters for the entries. This is all that it takes. 

To understand this modeling process more clearly, pay attention to the definition of the following child class, which not surprisingly has been named “BlogPost.” Here it is:

(Blog/Entity/BlogPost.php)

<?php

namespace BlogEntity;

class BlogPost extends EntityAbstract
{
    protected $_allowedFields = array(‘id’, ‘title’, ‘content’, ‘author’);
   
    /**
     * Set the blog post ID
     */
    public function setId($id)
    {
        if(!filter_var($id, FILTER_VALIDATE_INT, array(‘options’ => array(‘min_range’ => 1, ‘max_range’ => 99999)))) {
            throw new EntityException(‘The blog ID ‘ . $id . ‘ is invalid.’);
        }
        $this->_values['id'] = $id;
    }
   
    /**
     * Set the blog post title
     */ 
    public function setTitle($title)
    {
        if (!is_string($title) || strlen($title) < 2 || strlen($title) > 64) {
            throw new EntityException(‘The blog post title is invalid.’);
        }
        $this->_values['title'] = $title;
    }
   
    /**
     * Set the blog post content
     */ 
    public function setContent($content)
    {
        if (!is_string($content)) {
            throw new EntityException(‘The blog post content is invalid.’);
        }
        $this->_values['content'] = $content;
    }
   
    /**
     * Set the blog post author (usually this should be another entity. Now it will be a string for brevity)
     */
    public function setAuthor($author)
    {
        if (!is_string($author) || strlen($author) < 2 || strlen($author) > 32) {
            throw new EntityException(‘The blog post author is invalid.’);
        }
        $this->_values['author'] = $author;
    }       
}

Apart from seeing that PHP needs to support type hinting for primitive types like integers and strings, understanding the underlying logic of the “BlogPost” class is a breeze. Simply put, the class acts like a container that permits you to assign, via the corresponding mutators, the “id,” “title,” “content” and “author” to a given blog entry. Effectively, the methods impose some generic restrictions to these properties, which can be modified to suit more specific needs. So, feel free to play around with them.

In addition, you should notice that the setter for the “author” treats this property as a plain string. I’ve done this deliberately to keep the code sample short and uncluttered. However, in a real situation, the author should be a separate entity with its own attributes and constraints, which should be modeled by a separate subclass and handled by a specific data mapper. Make sure to stick to this approach, especially if you plan to use a domain layer in the development of your next killer PHP application.

So far, so good. At this point, the domain layer of this sample blog program is finally complete. But hold on a second! Wasn’t this supposed to be a series that explores the use of service locators? Well, it is. It’s just that the classes developed so far need no dependencies, as they only model entities.

Don’t feel concerned, though; in the next tutorial I’ll be building the data access and mapping layers of the blog, which will need to set up some object graphs to work correctly. Remember that in this first approach, those object graphs will use only injected collaborators. But, in upcoming parts I’ll be demonstrating how to get similar results using static and dynamic service locators.   

Final thoughts

In this third installment of the series, I went through the development of the domain layer of a sample blog application, which in this particular case (for the sake of simplicity) will be able to fetch, save, and delete blog post entries from the underlying storage layer.

In its current state, the blog program looks pretty skeletal. It’s only able to model the aforementioned blog entries. But this is about to change. As I said before, in the next tutorial I’ll be defining its data access and mapping layers. The latter will make use of dependency injection to construct its object graphs. But, keep in mind that I plan to deploy the application using static and dynamic service locators as well — so be ready to be faced with a huge amount of code samples.

Don’t miss the upcoming part!

[gp-comments width="770" linklove="off" ]
antalya escort bayan antalya escort bayan