Adding functionalities to the model class

Hi,

I am writing a basic PHP framework. I have an abstract model class :

abstract class Model {
   
    public function save() {
        /* Save data */
    }
   
    public function delete() {
        /* Delete a record */
    }
   
}

I create model classes extending the base Model class, for instance :

class ArticleModel extends Model {
    ...
}

I would like to add functionalities to my models in a flexible manner and so that I would be able to reuse them (publication, trash bin, translation…). I am wondering what kind of approach/pattern would be more suitable.

I already have a event system based on the observer pattern which allow me to attach listeners to an object. It’s quite useful but I need the ability to add new operations to existing object.

Should I use the Visitor pattern like this :

interface Visitable {
    function accept( Visitor $visitor );
}

interface Visitor {
    function visit(Visitable $visitable);
}

abstract class Model implements Visitable {
   
    public function accept( Visitor $visitor ) {
        $visitor->visit( $this );
    }

    public function save() {
        /* Save data */
    }
   
    public function delete() {
        /* Delete a record */
    }
   
}

Then I define some useful visitor classes :

class SoftDeleteVisitor implements Visitor {
    public function visit(Visitable $visitable) {
        $visitable->is_deleted = 1;
        $visitable->save();
    }
}

class TranslateVisitor implements Visitor {
    public function visit(Visitable $visitable) {
        /* Translate columns */
    }
}

$article = new ArticleModel();
$article = $article->findOne( 6 ); /* There is no late static binding in PHP5.2... */

$article->accept( new TranslateVisitor( array( 'title', 'text') ) );

$article->accept( new SoftDeleteVisitor() );
/* performs a soft deletion : is_deleted = 1 */

Or should I use Decorators instead :

$article = new ArticleModel();
$article = new SoftDeleteDecorator( $article->findOne( 6 ) );
$article->delete();

The SoftDeleteDecorator would for instance “override” the delete() method and add a restore() method.

Or should I simply use static classes like this :

class SoftDeleter {
    public static delete( $target ) {
        $target->is_deleted = 1;
        $target->save();
    }
}

$article = new ArticleModel();
$article = $article->findOne( 6 ); 

SoftDeleter->delete( $article );

Whatever you do, try to keep this functionality away from the user (so it’s easy to use).

Ex, you want this:


class ArticleModel extends Model {
    # Don't call parent delete
    public function delete() {
        $this->deleted = 1;
        $this->save();
    }
} 


# Usage
$article = new ArticleModel();
$article = $article->findOne( 6 );
$article->delete();

But in a dynamic way.

So, you can do something like:


# Component
class TrashBin {
  public static function delete(Model $obj) {
    $obj->deleted = 1;
    $obj->save();
    return true; # don't run any other component after this
  }
}

# Your main model
abstract class Model {
  public function __construct() {
    $this->extends('DTOBasic'); # Adds SELECT/UPDATE/DELETE/INSERT functionality.
    $this->extends('DTOSearch');  # Ads findWhere(), findOne(), etc
  }
 
 # Every function will call the components function, if any.
 public function __call($name, $arguments) {
   array_unshift($arguments, $this);
   foreach($components as $component) {
      if (call_user_func_array(array($component, $name), $arguments)) {
        break;
      }
    }
 }
}

# Your Article DTO, with special delete
class ArticleModel extends Model {
    # Object constructor will say what components to use
    public function __construct() {
      $this->extends('TrashBin');        # Delete will update the "delete" flag.
      $this->extends('Translation');     # Translates some fields on get
      parent::__construct();
    }
} 


# Usage
$article = new ArticleModel();
$article = $article->findOne( 6 );
$article->delete();

You end up with something like multiple inheritance.
It’s very dynamic, as in you can add any functionality you want on the fly, and it’s all transparent to the programmers using your objects, BUT they can see what functionality each object has by looking at the constructor.

The down sides…

  • it will be weird to keep your DB tables in sync with your components. (ex: the delete field) So you need some way for your components NOT to use the same fields, and to let you know what fields you need on your db table.
  • your components are added by class name (or some constant), so if your IDE has auto-complete, that won’t work, unless you add the doc types.
  • if you have 5 components with a delete() function, you have to remember what gets called first (so the code for it is not one click away)
  • it kind of breaks OOP, since everything is dynamic, maybe to dynamic, it works great in PHP, but in Java you will have a hard time to code this.
  • might not be as fast as the first example.
  • once you make your framework, and use it a bit, you will have a HARD time moving away from it, since if done right, it will be to easy to use/reuse, but not many people use it.