SoFunction
Updated on 2025-04-04

PHP object-oriented work unit (example explanation)

Work unit

This model involves domain models, data mappers and identification mappings, which will be sorted out and reviewed here.

$venue = new \woo\domain\Venue(null,"The Green Tree");

\woo\domain\ObjectWatcher::instance()->performOperations();

Now the above two lines of client code are a starting point to describe how this pattern works.

The first sentence: When creating an object using the domain model object, it calls the Identification Map ObjectWatcher class

Mark yourself as an object that needs to be added. The performOperations method of the second sentence will be stored in the attribute $new of the identification mapper

Insert into the database. Note that the $obj->finder() method called internally is to generate a corresponding data mapper class through the HelperFactory factory class in the domain pattern and return it.

There is no specific implementation under the HelperFactory class (the original text is not implemented either). In fact, it is to use the conditional branch to create the corresponding data mapper based on the type of the class passed in the parameters.

Let’s take a look at the code and comments to understand.

namespace woo\domain;

//Identity Mapclass ObjectWatcher{
  
  private $all = array();        //The small warehouse for storing objects  private $dirty = array();      //Storing objects that need to be modified in the database  private $new = array();        //Storing objects that need to be added in the database  private $delete = array();      //Storage objects that need to be deleted in the database  private static $instance;      //Single  
  
  private function __construct (){}
  
  static function instance(){
    if(!self::$instance){
      self::$instance = new ObjectWatcher();
    }
    return self::$instance;
  }
  
  //Get a unique identifier. Here we use the method of domain class name + ID to create a unique identifier to avoid the problem of duplication of ID when multiple database tables call this class.  function globalKey(DomainObject $obj){
    $key = get_class($obj) . "." . $obj->getId();
    return $key;
  }
  
  //Add an object  static function add(DomainObject $obj){
    $inst = self::instance();
    $inst->all[$inst->globalKey($obj)] = $obj;
  }
  
  //Get object  static function exists($classname,$id){
    $inst = self::instance();
    $key = "$classname.$id";
    if(isset($inst->all[$key]){
      return $inst->all[$key];
    }
    return null;
  }
  
  //Tag as object to be deleted  static function addDelete(DomainObject $obj){
    $self = self::instance();
    $self->delete[$self->globalKey($obj)] = $obj;
  }
  
  //Tag as object that needs to be modified  static function addDirty(DomainObject $obj){
    $inst = self::instance();
    if(!in_array($obj,$inst->new,true)){
      $inst->dirty[$inst->globalKey($obj)] = $obj;
    }
  }
  
  // Mark as an object that needs to be added  static function addNew(DomainObject $obj){
    $inst = self::instance();
    $inst->new[] = $obj;
  }
  
  //Tagged as clean object  static function addClean(DomainObject $obj){
    $self = self::instance();
    unset($self->delete[$self->globalKey($obj)]);
    unset($self->dirty[$self->globalKey($obj)]);
    $self->new = array_filter($self->new,function($a) use($obj) {return !($a === $obj);});
  }
    
  //Interact the above objects that need to be added, deleted and modified with the database for processing  function performOperations(){
    foreach($this->dirty as $key=>$obj){
      $obj->finder()->update($obj);    //$obj->finder() gets a data mapper    }
    foreach($this->new as $key=>$obj){
      $obj->finder()->insert($obj);
    }
    $this->dirty = array();
    $this->new = array();
  }
}


//Domain Modelabstract class DomainObject{      //Abstract base class  
  private $id = -1;
  
  function __construct ($id=null){
    if(is_null($id)){
      $this->markNew();      //It is marked as an object that needs to be added during initialization    } else {
      $this->id = $id;
    }  
  }
  
  //The method of marking the object of the marker is called  function markNew(){
    ObjectWatcher::addNew($this);
  }
  
  function markDeleted(){
    ObjectWatcher::addDelete($this);
  }
  
  function markDirty(){
    ObjectWatcher::addDirty($this);
  }
  
  function markClean(){
    ObjectWatcher::addClean($this);
  }
  
  function setId($id){
    $this->id = $id;
  }
  
  function getId(){
    return $this->id;
  }
  
  
  function finder(){
    return self::getFinder(get_class($this));
  }
  
  //Instantiate a specific type of data mapper object through factory classes, such as VenueMapper  //This object will be called by the performOperations method in the identification mapper for interaction with the database for addition, deletion and modification operations.  static function getFinder($type){
    return HelperFactory::getFinder($type);
  }
  
}


class Venue extends DomainObject {
  private $name;
  private $spaces;
  
  function __construct ($id = null,$name=null){
    $this->name= $name;
    $this->spaces = self::getCollection('\\woo\\domain\\space'); 
    parent::__construct($id);
  }
  
  function setSpaces(SpaceCollection $spaces){
    $this->spaces = $spaces;
    $this->markDirty();            //Tag as object that needs to be modified  }
  
  function addSpace(Space $space){
    $this->spaces->add($space);
    $space->setVenue($this);
    $this->markDirty();            //Tag as object that needs to be modified  }
  
  function setName($name_s){
    $this->name = $name_s;
    $this->markDirty();            //Tag as object that needs to be modified  }
  
  function getName(){
    return $this->name;
  }
}


//Domain Modelclass Space extends DomainObject{
  //.........
  function setName($name_s){
    $this->name = $name_s;
    $this->markDirty();
  }
  
  function setVenue(Venue $venue){
    $this->venue = $venue;
    $this->markDirty();
  }
}


//Data mapperabstract class Mapper{
  
  abstract static $PDO;    //Operate the pdo object of the database  function __construct (){
    if(!isset(self::$PDO){
      $dsn = \woo\base\ApplicationRegistry::getDSN();
      if(is_null($dsn)){
        throw new \woo\base\AppException("no dns");
      }
      self::$PDO = new \PDO($dsn);
      self::$PDO->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION);
    }
  }
  
  //Get the tagged object  private function getFroMap($id){
    return \woo\domain\ObjectWatcher::exists($this->targetClass(),$id);
  }
  
  
  //Add a new tagged object  private function addToMap(\woo\domain\DomainObject $obj){//////
    return \woo\domain\ObjectWatcher::add($obj);
  }
  
  
  //Map the database data into an object  function createObject($array){
    $old = $this->getFromMap($array['id']);
    if($old){return $old;}
    $obj = $this->doCreateObject($array);
    $this->addToMap($obj);
    $obj->markClean();
    return $obj;
  }

  
  function find($id){                // Get a data from the database through ID and create it as an object    $old = $this->getFromMap($id);        
    if($old){return $old}            
    
    $this->selectStmt()->execute(array($id));
    $array= $this->selectStmt()->fetch();
    $this->selectStmt()->closeCursor();
    if(!is_array($array)){
      return null;
    }
    if(!isset($array['id'])){
      return null;
    }
    $object = $this->createObject($array);
    $this->addToMap($object);          
    return $object;  
  }
  
  
  function insert(\woo\domain\DomainObject $obj){      //Insert object data into the database    $this->doInsert($obj);
    $this->addToMap($obj);            
  }
  
  //Each abstract method required to implement in subclass  abstract function targetClass();                    //Get the type of the class  abstract function update(\woo\domain\DomainObject $objet);        //Modify the operation  protected abstract function doCreateObject(array $array);        //Create an object  protected abstract function selectStmt();                //Query operation  protected abstract function doInsert(\woo\domain\DomainObject $object);  //Insert operation  
}

class VenueMapper extends Mapper {
  function __construct (){    
    parent::__construct();  
    //Preprocessing object    $this->selectStmt = self::$PDO->prepare("select * from venue where id=?");
    $this->updateStmt = self::$PDO->prepare("update venue set name=?,id=? where id=?");
    $this->insertStmt = self::$PDO->prepare("insert into venue (name) values(?)");
  }
  
  protected function getCollection(array $raw){    //Convert Space array to object collection    return new SpaceCollection($raw,$this);        
  }
  
  protected function doCreateObject (array $array){  //Create an object    $obj = new \woo\domain\Venue($array['id']);
    $obj->setname($array['name']);
    return $obj;
  }
  
  protected function doInsert(\woo\domain\DomainObject $object){ //Insert the object into the database    print 'inserting';
    debug_print_backtrace();
    $values = array($object->getName());
    $this->insertStmt->execute($values);
    $id = self::$PDO->lastInsertId();
    $object->setId($id);
  }
  
  function update(\woo\domain\DomainObject $object){    //Modify database data    print "updation\n";
    $values = array($object->getName(),$object->getId(),$object->getId());
    $this->updateStmt->execute($values);
  }
  
  function selectStmt(){          //Return a preprocessed object    return $this->selectStmt;
  }
  
}


//Client$venue = new \woo\domain\Venue(null,"The Green Tree");        //It is marked as a new object when initialized$venue->addSpace(new \woo\domain\Space(null,"The Space Upstairs"));  //The addSpace method of these two lines will not be marked as a modified object because the venue has been marked as a new object, but space will be marked as a new object when initializing it.$venue->addSpace(new \woo\domain\Space(null,"The Bar Stage"));
\woo\domain\ObjectWatcher::instance()->performOperations();      //Added a new interaction with the databaseVenuedata,And twospacedata

The above PHP object-oriented work unit (example explanation) is all the content I share with you. I hope you can give you a reference and I hope you can support me more.