Как изменить имя Zend_Db_Table в модели для вставки в несколько таблиц

Используя Zend Framework, я создал модель для вставки записи в базу данных. У меня вопрос: после $this->insert($data) как я могу переключить активную таблицу, чтобы я мог вставить запись в другую таблицу?

Вот мой код:

class Model_DbTable_Foo extends Zend_Db_Table_Abstract
{
  protected $_name = 'foo';

  public function addFoo($params)
  {
    $data = array(
      'foo' => $params['foo'],
    );
    $this->insert($data);
    $foo_id = $this->getAdapter()->lastInsertId();

    $data2 = array(
      'bar' => $params['bar']
    );
    // I need to change the Db Table name here.
    $this->insert($data2);
    $bar_id = $this->getAdapter()->lastInsertId();
  }
}

person jwhat    schedule 12.03.2010    source источник


Ответы (3)


Zend_Db_Table - это шлюз табличных данных. Это

действует как шлюз к таблице базы данных. Один экземпляр обрабатывает все строки в таблице.

Это означает, что у вас есть один класс на таблицу. Ваш Model_DbTable_Foo представляет таблицу Foo в вашей базе данных и только эту таблицу. Он не должен делать вставки в другие таблицы. Для этого вы бы использовали другой класс таблицы. Самым чистым вариантом было бы добавить еще один слой поверх ваших TDG, который знает, как обрабатывать вставки в несколько таблиц, например

class Model_Gateway_FooBar
{
    protected $_tables;

    public function __construct(Zend_Db_Table_Abstract $foo, 
                                Zend_Db_Table_Abstract $bar)
    {
        $this->_tables['foo'] = $foo;
        $this->_tables['bar'] = $bar;
    }

    public function addFoo($data)
    {
        $this->_tables['foo']->insert($data['foo']);
        // yaddayaddayadda
        $this->_tables['bar']->insert($data['bar']);
    }
}

Однако это ваше приложение, и вы можете решить не беспокоиться и просто создать новый экземпляр другого класса в классе Foo и выполнить вставку оттуда, например

$otherTable = new Model_DbTable_Bar;
$otherTable->insert($data);

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

Кстати, когда вы выполняете несколько вставок, вы можете захотеть использовать транзакции, чтобы обе вставки работали должным образом, например

$this->_tables['foo']->getAdapter()->beginTransaction();

а затем commit() или rollback() в зависимости от результата запроса.

Также обратите внимание, что начиная с ZF1.9 вы также можете создавать экземпляры Zend_Db_Table без предварительного определения конкретного подкласса, например

$fooTable = new Zend_Db_Table('foo');

См. Главу о Zend_Db_Table в Справочном руководстве ZF.

person Gordon    schedule 12.03.2010
comment
Отличный совет! Я совсем забыл о транзакциях, я определенно хочу ими воспользоваться. Спасибо! - person jwhat; 13.03.2010
comment
Гордон, не могли бы вы объяснить, почему я хочу ввести cast $ foo и $ bar в конструкторе как Zend_Db_Table_Abstract вместо моих пользовательских Model_DbTable_Foo и Model_DbTable_Bar? - person jwhat; 13.03.2010
comment
Просто примечание для всех, кто интересуется транзакциями MySQL: мне пришлось изменить тип моей БД с MyISAM на InnoDB для поддержки транзакций. - person jwhat; 13.03.2010
comment
@j что это не тип cast, а тип подсказка. См. php.net/manual/en/language.oop5.typehinting.php - здесь вы можете использовать свои собственные классы моделей, но это свяжет ваши конкретные классы моделей со шлюзом. При использовании абстрактного класса для подсказки вы должны убедиться, что переданные экземпляры являются (просто) экземплярами таблиц. Они не обязательно являются вашими пользовательскими классами, но в данном случае суть состоит в том, чтобы убедиться, что экземпляры имеют методы Zend_Db_Table_Abstract. Это также более гибко, если вам нужно заменить пользовательский класс чем-то другим. - person Gordon; 14.03.2010
comment
@jwhat В двух словах: всегда лучше полагаться на абстрактные типы (интерфейсы, абстрактные базовые классы), чем на конкретные типы. Это позволяет вам изменять реализацию метода, не затрагивая ни одного из его вызывающих. - person Gordon; 14.03.2010

Я думаю, тебе стоит взять еще Model_DbTable, Model_DbTable_Bar и называть его либо

внутри:

class Model_DbTable_Foo ... {
  public function addFooAndBar() {
    ...
    $bar = new Model_DbTable_Bar();
    $bar->insert($data2);
  }
}

или внешне:

class ModelX ... {
  public function addFoos() {
    $foo = new Model_DbTable_Foo();
    $foo->insert($data);
    $bar = new Model_DbTable_Bar();
    $bar->insert($data2);
  }
}
person chelmertz    schedule 12.03.2010
comment
Уникальные классы для уникальных таблиц имеют смысл и кажутся чище. Спасибо! - person jwhat; 13.03.2010

Также вы можете использовать класс Zend_Db_Table. Что-то вроде этого:

 $fooTbl = new Zend_Db_Table('foo');
 $lastFooID = $fooTbl->insert($data2)
                     ->getAdapter()
                     ->lastInsertId();
person RDK    schedule 03.10.2012