Как установить наследование нескольких таблиц в домене с помощью Zend Framework? - PullRequest
2 голосов
/ 17 декабря 2008

У меня есть структура базы данных, в которой есть таблица Person, которая содержит поля, такие как имя, адрес электронной почты, company_id, personType и тому подобное. Поскольку не все лица обязательно являются системными пользователями, у меня есть отдельная таблица User, которая определяет имя пользователя и пароль для тех пользователей, которые являются пользователями в системе.

У меня есть следующий код для определения шлюза табличных данных для таблицы Person:

class Model_Table_Person extends Zend_Db_Table_Abstract
{
    protected $_name = 'person';
    protected $_primary = 'person_id';

    protected $_referenceMap = array(
        'Company' =>    array(
            'columns' => 'company_id',
            'refTableClass' => 'Company',
            'refColumns' => 'id'
        ),
        'Store' =>  array(
            'columns' => 'store_id',
            'refTableClass' => 'Store',
            'refColumns' => 'id'
        )
    );

    public function findByPersonType(string $personType)
    {
        $where = $this->getAdapter()->quoteInto('personType = ?', $personType);
        return $this->fetchAll($where);
    }
}

И этот код определяет объект домена для Person:

class Model_Person
{
    protected static $_gateway;

    protected $_person;

    public static function init()
    {
        if(self::$_gateway == null)
        {
            self::$_gateway = new Model_Table_Person();
        }
    }

    public static function get(string $searchString, string $searchType = 'id') 
    {
        self::init();

        switch($searchString)
        {
            case 'id':
                $row = self::$_gateway->find($id)->current();
                break;
        }

        return self::factory($row);
    }

    public static function getCollection(string $searchString, string $searchType = null)
    {
        self::init();

        switch($searchType)
        {
            case 'userType':
                $row = self::$_gateway->findByPersonType($searchString);
                break;
            default:
                $personRowset = self::$_gateway->fetchAll();
                break;
        }

        $personArray = array ();

        foreach ($personRowset as $person)
        {
            $personArray[] = self::factory($person);
        }

        return $personArray;
    }

    public function getCompany()
    {
        return $this->_person->findParentRow('Company');
    }

    public function getStore()
    {
        return $this->_person->findParentRow('Store');
    }

    protected static function factory(Zend_Db_Table_Row $row) 
    {
        $class = 'Model_Person_' . ucfirst($row->personType);
        return new $class($row);
    }

    // protected constructor can only be called from this class, e.g. factory()
    protected function __construct(Zend_Db_Table_Row $personRow)
    {
        $this->_person = $personRow;
    }
}

Наконец, у меня есть еще один шлюз табличных данных для пользователя:

class Model_Table_User extends Zend_Db_Table_Abstract
{
    protected $_name = 'user';
    protected $_primary = 'person_id';

    public function findByUserName()
    {

    }
}

И базовый класс, который расширяет таблицу Model_Person следующим образом:

class Model_User extends Model_Person
{       
    public function login()
    {

    }

    public function setPassword()
    {

    }   
}

Как правильно расширить класс «Model_User» (который служит базовым типом для всех других типов пользователей, кроме одного), чтобы использовать функции класса «Model_Person», которые отображаются в одну таблицу, а также отображают фактические функции «Model_User» использовать вторую таблицу?

1 Ответ

1 голос
/ 17 декабря 2008

Это огромный недостаток для PHP (до версии 5.3.0) - отсутствие поддержки позднего статического связывания .

То есть, когда один статический метод, такой как get(), вызывает другой статический метод, такой как init(), он всегда использует метод init(), определенный в этом классе. Если подкласс определяет альтернативный метод init() и вызывает get(), ожидая, что он вызовет переопределенную версию init(), этого не произойдет.

class A
{
  static $var = null;
  static function init() { self::$var = 1234; }
  static function get() { self::init(); }
}

class B extends A
{
  static function init() { self::$var = 5678; }
}

B::get();
print B::$var . "\n"; 

Это печатает "1234", тогда как вы могли бы ожидать, что он напечатает "5678". Как будто A::get() не знает, что это часть класса B. Обходной путь заключается в том, что вы должны скопировать реализацию для метода get() в подкласс, даже если он ничем не отличается от суперкласса. Это очень неудовлетворительно .

PHP 5.3.0 пытается исправить это, но вы должны кодировать его немного по-другому в get():

function get() {
  static::init();
}

PHP 5.3.0 все еще находится в альфа-версии.


Есть несколько возможных путей решения проблемы:

  • Не делить подкласс Person как User, но вместо этого добавьте атрибуты логина и пароля в класс Person. Если эти атрибуты имеют значение NULL, то это не пользователь, и функции login() и setPassword() должны учитывать это и выдавать исключение или возвращать false или что-то еще.

  • Используйте разные get() методы для каждого подтипа: getUser(), getPerson() и т. Д. Каждый из них будет инициализировать свой собственный соответствующий объект таблицы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...