<?php

class MyException extends Exception {}

abstract class Thing
{
    protected $_child;

    protected $_name;

    protected $_selfId;

    /** @var  DataModel */
    protected $_model;

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

    /**
     * @return Thing
     */
    public function getChild()
    {
        return $this->_child;
    }

    public function setChild(Thing $child)
    {
        $this->_child = $child;
    }

    public function create()
    {
        if($this->getChild() != null){
            if($this->getChild()->create() == null){
                throw new MyException('Нет ' . $this->getChild()->getName());
            }
        }
        if(!$model = $this->_selfCreate()){
            if($this->getChild() != null){
                $this->getChild()->delete();
            }
            throw new MyException('Нет' . $this->getName());
        }
        return $model;
    }

    abstract protected function _selfCreate();

    public function delete()
    {
        if($this->getChild() != null){
            $this->getChild()->delete();
        }
        $this->selfDelete();
    }

    public function selfDelete()
    {
        $this->_model->delete();
    }

    public function getName()
    {
        return $this->_name;
    }

    public function getSelfId()
    {
        return $this->_selfId;
    }


}

abstract class DataModel
{

    public function __construct(){}
    /**
     * Может не создатся
     */
    public function create()
    {
        if(rand(1, 5) > 3){
            return true;
        }
        return false;
    }

    public function delete(){//delete
    }

    public function getId()
    {
        return rand();
    }
}

class RootDataModel extends DataModel{}

class MiddleDataModel extends DataModel
{
    public function create($child_id)
    {
        if(rand(1, 5) > 3){
            return true;
        }
        return false;
    }
}

class ProductDataModel extends DataModel
{
    protected $_some_prop;
    public function __construct($prop)
    {
        parent::__construct();
        $this->_some_prop = $prop;
    }

    public function create($child_id)
    {
        if(rand(1, 5) > 3){
            return true;
        }
        return false;
    }
}

class Root extends Thing
{
    protected function _selfCreate()
    {
        $model = new RootDataModel();
        if(!$model->create()){
            return null;
        }
        $this->_model = $model;
        $this->_selfId = $model->getId();
        return $model;
    }
}

class Middle extends Thing
{
    protected function _selfCreate()
    {
        $child_id = $this->getChild()->getSelfId();
        $model = new MiddleDataModel();
        if(!$model->create($child_id)){
            return null;
        }
        $this->_model = $model;
        $this->_selfId = $model->getId();
        return $model;

    }
}

class Product extends Thing
{
    protected $_some_model_prop;

    public function __construct($name, $prop)
    {
        parent::__construct($name);
        $this->_some_model_prop = $prop;
    }

    protected function _selfCreate()
    {
        $child_id = $this->getChild()->getSelfId();
        $model = new ProductDataModel($this->_some_model_prop);
        if(!$model->create($child_id)){
            throw new MyException('Для продукта ' . $this->getName());
        }
        $this->_model = $model;
        $this->_selfId = $model->getId();
        return $model;

    }
}

class Factory
{
    /**
     * @param $prop
     * @return Product
     */
    public static function make($prop)
    {
        $root = new Root('root');
        $middle = new Middle('middle');
        $product = new Product('product', $prop);
        $middle->setChild($root);
        $product->setChild($middle);
        return $product;
    }
}

$some_prop = 'Ололо';
$product = Factory::make($some_prop);
try{
    $product->create();
} catch(MyException $e){
    echo $e->getMessage();
}
?>