*/ class mpProductCatalog { /** * GoF singleton instance. * * @type mpProductCatalog * @var mpProductCatalog $instance */ private static $instance = null; /** * GoF singleton method * * @return mpProductCatalog */ public static function getInstance() { if ( self::$instance === null ) { self::$instance = new mpProductCatalog(); } return self::$instance; } /** * List of existing products. * * @type array * @var array $products */ private $products = array(); /** * Private ctor */ private function __construct() { $this->products = (array) @unserialize( @file_get_contents( dirname( __FILE__ ) . "/../data/catalog.dat" ) ); } /** * Catalog destructor. */ public function __destruct() { file_put_contents( dirname( __FILE__ ) . "/../data/catalog.dat", serialize( $this->products ) ); } /** * Creates a new transaction for the product. * * @param mpProduct $product * @return mpProductTransaction */ public function createTransaction( mpProduct $product ) { return new mpProductTransaction( $product ); } /** * Adds the given product to the catalog. * * @param mpProduct $product * @throws mpProductExistsException */ public function addProduct( mpProduct $product ) { if ( isset( $this->products[$product->name] ) ) { throw new mpProductExistsException( $product->name ); } $this->products[$product->name] = $product; } } /** * Product transaction class. * * @author Manuel Pichler */ class mpProductTransaction { /** * List of open transactions. * * @type array * @var array $openTransactions */ private static $openTransactions = array(); /** * The context product. * * @type mpProduct * @var mpProduct $product */ private $product = null; /** * The transaction ctor. * * @param mpProduct $product */ public function __construct( mpProduct $product ) { $this->product = $product; } /** * Starts a new product transaction. * * @throws mpProductInTransactionException */ public function begin() { self::openTransaction( $this ); } /** * Commits the product transaction. * * @throws mpProductTransactionNotOpenException */ public function commit() { self::closeTransaction( $this ); } /** * Rolls the product transaction back. * * @throws mpProductTransactionNotOpenException */ public function rollback() { self::closeTransaction( $this ); } /** * Opens the given transaction. * * @param mpProductTransaction $transaction * @throws mpProductInTransactionException */ private static function openTransaction( mpProductTransaction $transaction ) { if ( isset( self::$openTransactions[$transaction->product->name] ) ) { throw new mpProductInTransactionException( $transaction->product->name ); } self::$openTransactions[$transaction->product->name] = true; } /** * Closes the given transaction. * * @param mpProductTransaction $transaction * @throws mpProductTransactionNotOpenException */ private static function closeTransaction( $transaction ) { if ( !isset( self::$openTransactions[$transaction->product->name] ) ) { throw new mpProductTransactionNotOpenException( $transaction->product->name ); } unset( self::$openTransactions[$transaction->product->name] ); } } /** * Simple product model. * * @author Manuel Pichler */ class mpProduct { /** * The product name. * * @type string * @var string $name */ public $name = null; /** * Product ctor. */ public function __construct( $name = null ) { $this->name = $name; } } /** * Exception * * @author Manuel Pichler */ class mpProductExistsException extends RuntimeException { /** * Exception ctor. * * @param string $name */ public function __construct( $name ) { parent::__construct( "A product '{$name}' already exists." ); } } /** * Exception * * @author Manuel Pichler */ class mpProductInTransactionException extends RuntimeException { /** * Exception ctor. * * @param string $name */ public function __construct( $name ) { parent::__construct( "An open transaction for product '{$name}' already exists." ); } } /** * Exception * * @author Manuel Pichler */ class mpProductTransactionNotOpenException extends RuntimeException { /** * Exception ctor. * * @param string $name */ public function __construct( $name ) { parent::__construct( "No open transaction for product '{$name}'." ); } }