| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976 |
- <sect1 id="zend.db.table.relationships">
- <title>Связи между таблицами Zend_Db_Table</title>
- <sect2 id="zend.db.table.relationships.introduction">
- <title>Введение</title>
- <para>
- В реляционной БД таблицы имеют связи друг с другом. Запись в таблице
- может быть связана с одной или более записей в другой таблице с
- использованием ограничений ссылочной целостности, определенных в
- конкретной БД.
- </para>
- <para>
- Класс Zend_Db_Table_Row имеет методы для запрашивания связанных
- строк в другой таблице.
- </para>
- </sect2>
- <sect2 id="zend.db.table.relationships.defining">
- <title>Определение связей</title>
- <para>
- Определите классы для каждой из ваших таблиц, расширяя абстрактный
- класс Zend_Db_Table_Abstract, как описано в <xref
- linkend="zend.db.table.defining" />. Также смотрите описание БД, для
- которой написан приведнный ниже код в
- <xref linkend="zend.db.adapter.example-database" />
- </para>
- <para>
- Ниже приведено определение классов для этих таблиц:
- </para>
- <programlisting language="php"><![CDATA[
- class Accounts extends Zend_Db_Table_Abstract
- {
- protected $_name = 'accounts';
- protected $_dependentTables = array('Bugs');
- }
- class Products extends Zend_Db_Table_Abstract
- {
- protected $_name = 'products';
- protected $_dependentTables = array('BugsProducts');
- }
- class Bugs extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs';
- protected $_dependentTables = array('BugsProducts');
- protected $_referenceMap = array(
- 'Reporter' => array(
- 'columns' => 'reported_by',
- 'refTableClass' => 'Accounts',
- 'refColumns' => 'account_name'
- ),
- 'Engineer' => array(
- 'columns' => 'assigned_to',
- 'refTableClass' => 'Accounts',
- 'refColumns' => 'account_name'
- ),
- 'Verifier' => array(
- 'columns' => array('verified_by'),
- 'refTableClass' => 'Accounts',
- 'refColumns' => array('account_name')
- )
- );
- }
- class BugsProducts extends Zend_Db_Table_Abstract
- {
- protected $_name = 'bugs_products';
- protected $_referenceMap = array(
- 'Bug' => array(
- 'columns' => array('bug_id'),
- 'refTableClass' => 'Bugs',
- 'refColumns' => array('bug_id')
- ),
- 'Product' => array(
- 'columns' => array('product_id'),
- 'refTableClass' => 'Products',
- 'refColumns' => array('product_id')
- )
- );
- }
- ]]>
- </programlisting>
- <para>
- Если вы используете Zend_Db_Table для эмулирования каскадных
- операций обновления и удаления, то объявите массив
- <varname>$_dependentTables</varname> в классе для
- родительской таблицы. Перечислите имена классов всех зависимых
- таблиц. Используйте имена классов, а не таблиц в БД.
- </para>
- <note>
- <para>
- Пропустите объявление массива <varname>$_dependentTables</varname>,
- если используете ограничения ссылочной на сервере СУРБД для
- реализации каскадных операций. См.
- <xref linkend="zend.db.table.relationships.cascading" /> для
- получения более подробной информации.
- </para>
- </note>
- <para>
- Объявите массив <varname>$_referenceMap</varname> во всех классах
- зависимых таблиц. Это ассоциативный массив "правил связей". Правило
- связи определяет, какая таблица является родительской в конкретной
- связи, и какие столбцы в зависимой таблице ссылаются на какие
- столбцы в родительской таблице.
- </para>
- <para>
- Ключом правила является строка, используемая как индекс массива
- <varname>$_referenceMap</varname>. Этот ключ правила используется для
- идентификации каждой связи. Выбирайте для него описательное имя.
- Лучше всего использовать строку, которая может быть частью имени
- метода, как вы увидите позднее.
- </para>
- <para>
- В примере выше ключами правил являются:
- <code>'Reporter'</code>,
- <code>'Engineer'</code>,
- <code>'Verifier'</code>, и
- <code>'Product'</code>.
- </para>
- <para>
- Значением каждого правила в массиве <varname>$_referenceMap</varname>
- является также ассоциативный массив. Элементы этого массива описаны
- ниже:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>columns</emphasis> =>
- Строка или массив строк с имен(ем/ами)
- столбцов внешних ключей в зависимой таблице.
- </para>
- <para>
- Обычно это один столбец, но некоторые таблицы имеют
- составные ключи.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>refTableClass</emphasis> =>
- Имя класса родительской таблицы. Используйте имя класса, а
- не таблицы в БД.
- </para>
- <para>
- Обычно зависимые таблицы имеют одну связь со своей
- родительской таблицей, но некоторые таблицы имеют
- множественные связи с одной и той же родительской таблицей.
- В базе данных, которую мы рассматриваем для примера, таблица
- <code>bugs</code> ссылается на таблицу
- <code>products</code>, но имеет также три связи с таблицей
- <code>accounts</code>.
- Помещайте каждую ссылку в отдельную запись в массиве
- <varname>$_referenceMap</varname>.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>refColumns</emphasis> =>
- Строка или массив строк, в котором перечислены имена
- столбцов первичного ключа в родительской таблице.
- </para>
- <para>
- Обычно это один столбец, но некоторые таблицы имеют
- составные ключи. Если ссылка использует составной ключ, то
- порядок столбцов в элементе <code>'columns'</code> должен
- соответствовать порядку столбцов в элементе
- <code>'refColumns'</code>.
- </para>
- <para>
- Этот элемент является опциональным. Если вы не определите
- <code>refColumns</code>, то по умолчанию используются имена
- столбцов, объявленных как столбцы первичных ключей
- родительской таблицы.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>onDelete</emphasis> =>
- Правило для действия, выполняемого, когда в родительской
- таблице удаляется строка. См.
- <xref linkend="zend.db.table.relationships.cascading" />
- для получения более подробной информации.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>onUpdate</emphasis> =>
- Правило для действия, выполняемого, когда изменяются
- значения в столбцах первичного ключа родительской таблицы.
- См.
- <xref linkend="zend.db.table.relationships.cascading" /> для
- получения более подробной информации.
- </para>
- </listitem>
- </itemizedlist>
- </sect2>
- <sect2 id="zend.db.table.relationships.fetching.dependent">
- <title>Извлечение зависимых строк</title>
- <para>
- Если вы имеете объект Row (строка) в результате запроса к
- родительской таблице, то можете извлечь строки из зависимых
- таблиц, ссылающихся на текущую строку.
- Используйте следующий метод:
- </para>
- <programlisting language="php">
- <![CDATA[
- $row->findDependentRowset($table, [$rule]);
- ]]>
- </programlisting>
- <para>
- Этот метод возвращает объект Zend_Db_Table_Rowset_Abstract,
- содержащий набор строк из зависимой таблицы <varname>$table</varname>,
- ссылающихся на строку, представленную объектом <varname>$row</varname>.
- </para>
- <para>
- Первый аргумент <varname>$table</varname> может быть строкой с именем
- класса зависимой таблицы. Вы можете также определить зависимую
- таблицу, используя объект класса этой таблицы.
- </para>
- <example id="zend.db.table.relationships.fetching.dependent.example">
- <title>Извлечение зависимых строк</title>
- <para>
- Этот пример демонстрирует получение объекта строки из таблицы
- <code>Accounts</code> и поиск ошибок в таблице
- <code>Bugs</code>, о которых сообщил данный пользователь.
- </para>
- <programlisting language="php">
- <![CDATA[
- $accountsTable = new Accounts();
- $accountsRowset = $accountsTable->find(1234);
- $user1234 = $accountsRowset->current();
- $bugsReportedByUser = $user1234->findDependentRowset('Bugs');
- ]]>
- </programlisting>
- </example>
- <para>
- Втрой аргумент <varname>$rule</varname> является опциональным. Это строка
- с ключом правила в массиве <varname>$_referenceMap</varname> класса
- зависимой таблицы.
- Если вы не определите правило, то будет использоваться первое
- правило из массива, ссылающееся на родительскую таблицу.
- Для того, чтобы использовать правило, отличное от первого,
- необходимо указать ключ.
- </para>
- <para>
- В примере выше ключ правила не определен, поэтому используется
- первое правило, соответствующее родительской таблице. Это будет правило <code>'Reporter'</code>.
- </para>
- <example id="zend.db.table.relationships.fetching.dependent.example-by">
- <title>Извлечение зависимых строк по определенному правилу</title>
- <para>
- Этот пример демонстрирует получение строки из таблицы
- <code>Accounts</code> и поиск ошибок в таблице
- <code>Bugs</code>, устранение которых назначено данному
- пользователю. Ключ правила, соответствующий этой связи в данном
- примере - <code>'Engineer'</code>.
- </para>
- <programlisting language="php"><![CDATA[
- $accountsTable = new Accounts();
- $accountsRowset = $accountsTable->find(1234);
- $user1234 = $accountsRowset->current();
- $bugsAssignedToUser = $user1234->findDependentRowset('Bugs', 'Engineer');
- ]]>
- </programlisting>
- </example>
- <para>
- <example id="zend.db.table.relationships.fetching.dependent.example-by-select">
- <title>Извлечение зависимых строк с использованием Zend_Db_Table_Select</title>
- <para>
- Этот пример демонстрирует получение объекта строки из
- таблицы <code>Accounts</code> и поиск ошибок в таблице
- <code>Bugs</code>, устранение которых назначено данному
- пользователю. При этом извлекается не более 3-х строк и они
- должны быть отсортированы по имени.
- </para>
- <programlisting language="php"><![CDATA[
- $accountsTable = new Accounts();
- $accountsRowset = $accountsTable->find(1234);
- $user1234 = $accountsRowset->current();
- $select = $accountsTable->select()->order('name ASC')
- ->limit(3);
- $bugsAssignedToUser = $user1234->findDependentRowset('Bugs',
- 'Engineer',
- $select);
- ]]>
- </programlisting>
- </example>
- Вы можете также запрашивать строки из зависимой таблицы, используя
- специальный механизм -так называемые "магические методы".
- Zend_Db_Table_Row_Abstract вызывает метод:
- <code>findDependentRowset('<TableClass>', '<Rule>')</code>,
- если вы вызываете метод объекта строки,
- соответствующий одному из следующих шаблонов:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <varname>$row->find<TableClass>()</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>$row->find<TableClass>By<Rule>()</varname>
- </para>
- </listitem>
- </itemizedlist>
- <para>
- В этих шаблонах <code><TableClass></code> и
- <code><Rule></code> являются именем класса зависимой таблицы
- и ключом правила зависимой таблицы, ссылающегося на родительскую
- таблицу.
- </para>
- <note>
- <para>
- Некоторые фреймворки приложений, такие, как Ruby on Rails,
- используют механизм, называемый "инфлексией" (inflection), и
- состоящий в изменении написания идентификаторов в зависимости от
- использования. Для простоты Zend_Db_Table_Row не предоставляет
- никакого механизма инфлексии. Имя таблицы и ключ правила в
- вызовах методов должны в точности соответствовать написанию
- имени класса таблицы и ключа правила при объявлении.
- </para>
- </note>
- <example id="zend.db.table.relationships.fetching.dependent.example-magic">
- <title>Извлечение зависимых строк с использованием магического
- метода</title>
- <para>
- Этот пример демонстрирует поиск зависимых строк, эквивалентный
- тому, что был в предыдущих примерах. В данном случае приложение
- использует вызов магического метода вместо передачи имени
- таблицы и ключа правила в качестве аргументов.
- </para>
- <programlisting language="php"><![CDATA[
- $accountsTable = new Accounts();
- $accountsRowset = $accountsTable->find(1234);
- $user1234 = $accountsRowset->current();
- // Используется правило связи по умолчанию
- $bugsReportedBy = $user1234->findBugs();
- // Задается правило связи
- $bugsAssignedTo = $user1234->findBugsByEngineer();
- ]]>
- </programlisting>
- </example>
- </sect2>
- <sect2 id="zend.db.table.relationships.fetching.parent">
- <title>Извлечение родительской строки</title>
- <para>
- Если вы имеете объект Row в результате запроса к зависимой таблице,
- то можете извлечь ту строку из родительской таблицы, на которую
- ссылается зависимая строка.
- Используйте метод:
- </para>
- <programlisting language="php"><![CDATA[
- $row->findParentRow($table, [$rule]);
- ]]>
- </programlisting>
- <para>
- Зависимая строка всегда должна ссылаться только на одну строку в
- родительской таблице, поэтому этот метод возвращает объект Row, а не
- Rowset.
- </para>
- <para>
- Первый аргумент <varname>$table</varname> может быть строкой с именем
- класса родительской таблицы. Вы можете также задавать родительскую
- таблицу, используя объект класса этой таблицы.
- </para>
- <example id="zend.db.table.relationships.fetching.parent.example">
- <title>Извлечение родительской строки</title>
- <para>
- Этот пример демонстрирует получение объекта Row из таблицы
- <code>Bugs</code> (для примера, одна из этих ошибок имеет статус
- 'NEW') и поиск строки в таблице <code>Accounts</code>,
- соответствующей пользователю, сообщившем об этой ошибке.
- </para>
- <programlisting language="php"><![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?' => 'NEW'));
- $bug1 = $bugsRowset->current();
- $reporter = $bug1->findParentRow('Accounts');
- ]]>
- </programlisting>
- </example>
- <para>
- Второй аргумент <varname>$rule</varname> является опциональным. Это строка
- с ключом правила в массиве <varname>$_referenceMap</varname> класса
- зависимой таблицы.
- Если вы не определите правило, то будет использоваться первое
- правило в массиве, ссылающееся на родительскую таблицу.
- Для того, чтобы использовать правило, отличное от первого,
- необходимо указать ключ.
- </para>
- <para>
- В примере кода выше ключ правила не определен, поэтому используется
- первое правило, соответствующее родительской таблице. Это будет
- правило <code>'Reporter'</code>.
- </para>
- <example id="zend.db.table.relationships.fetching.parent.example-by">
- <title>Извлечение родительской строки по определенному правилу</title>
- <para>
- Этот пример демонстрирует получение объекта Row из таблицы
- <code>Bugs</code> и поиск аккаунта пользователя, которому
- назначено исправление этой ошибки. Ключ правила,
- соответствующего этой связи в данном примере -
- <code>'Engineer'</code>.
- </para>
- <programlisting language="php"><![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
- $bug1 = $bugsRowset->current();
- $engineer = $bug1->findParentRow('Accounts', 'Engineer');
- ]]>
- </programlisting>
- </example>
- <para>
- Вы можете также запрашивать строки из родительской таблицы,
- используя "магический метод".
- Zend_Db_Table_Row_Abstract вызывает метод:
- <code>findParentRow('<TableClass>', '<Rule>')</code>,
- если вы вызываете метод объекта Row, соответствующий одному из
- следующих шаблонов:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <varname>$row->findParent<TableClass>([Zend_Db_Table_Select $select])</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>$row->findParent<TableClass>By<Rule>([Zend_Db_Table_Select
- $select])</varname>
- </para>
- </listitem>
- </itemizedlist>
- <para>
- В этих шаблонах <code><TableClass></code> и
- <code><Rule></code> - соответственно имя класса родительской
- таблицы и ключ правила зависимой таблицы, ссылающегося на
- родительскую таблицу.
- </para>
- <note>
- <para>
- Имя таблицы и ключ правила в вызовах методов должны в точности
- соответствовать написанию имени класса таблицы и ключа правила
- при объявлении.
- </para>
- </note>
- <example id="zend.db.table.relationships.fetching.parent.example-magic">
- <title>Извлечение родительской строки с использованием магического метода</title>
- <para>
- Этот пример демонстрирует поиск родительской строки,
- эквивалентный тому, что был в предыдущих примерах. В данном
- случае используется вызов магического метода вместо передачи
- имени таблицы и ключа правила в качестве аргументов.
- </para>
- <programlisting language="php"><![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->fetchAll(array('bug_status = ?', 'NEW'));
- $bug1 = $bugsRowset->current();
- // Используется правило связи по умолчанию
- $reporter = $bug1->findParentAccounts();
- // Задается правило связи
- $engineer = $bug1->findParentAccountsByEngineer();
- ]]>
- </programlisting>
- </example>
- </sect2>
- <sect2 id="zend.db.table.relationships.fetching.many-to-many">
- <title>Извлечение строк через связи "многие-ко-многим"</title>
- <para>
- Если вы имеете объект Row в результате выполнения запроса к одной из
- таблиц, находящихся в связи "многие-ко-многим" (в рамках данного
- примера будем называть эту таблицу "исходной"), вы можете извлечь
- соответствующие строки в другой таблице ("целевая" таблица) через
- таблицу пересечений. Используйте метод:
- </para>
- <programlisting language="php">
- <![CDATA[
- $row->findManyToManyRowset($table,
- $intersectionTable,
- [$rule1,
- [$rule2,
- [Zend_Db_Table_Select $select]
- ]
- ]);
- ]]>
- </programlisting>
- <para>
- Этот метод возвращает объект Zend_Db_Table_Rowset_Abstract,
- содержащий строки из таблицы <varname>$table</varname>, соответствующие
- связи "многие-ко-многим". Текущий объект строки <varname>$row</varname>
- исходной таблицы используется в поиске строк в таблице пересечений
- и производится объединение с целевой таблицей.
- </para>
- <para>
- Первый аргумент <varname>$table</varname> может быть именем класса целевой
- таблицы в связи "многие-ко-многим". Вы можете также задавать целевую
- таблицу, используя объект класса этой таблицы.
- </para>
- <para>
- Второй аргумент <varname>$intersectionTable</varname> может быть именем
- класса таблицы пересечений между двумя таблицами в связи
- "многие-ко-многим". Вы можете также задавать таблицу пересечений,
- используя объект класса этой таблицы.
- </para>
- <example id="zend.db.table.relationships.fetching.many-to-many.example">
- <title>Извлечение строк через метод для связей "многие-ко-многим"</title>
- <para>
- Этот пример демонстрирует получение объекта Row из исходной
- таблицы <code>Accounts</code> и поиск строк в целевой таблице
- <code>Products</code>, соответствующих продуктам, об ошибках в
- которых сообщил этот пользователь.
- </para>
- <programlisting language="php"><![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->find(1234);
- $bug1234 = $bugsRowset->current();
- $productsRowset = $bug1234->findManyToManyRowset('Products',
- 'BugsProducts');
- ]]>
- </programlisting>
- </example>
- <para>
- Третий и четвертый аргументы - <varname>$rule1</varname> и
- <varname>$rule2</varname> - являются опциональными. Это строки с ключами
- правил в массиве <varname>$_referenceMap</varname> класса таблицы
- пересечений.
- </para>
- <para>
- <varname>$rule1</varname> должен содержать ключ правила для ссылок таблицы
- пересечений на исходную таблицу. В данном примере это связь между
- таблицами <code>BugsProducts</code> и <code>Bugs</code>.
- </para>
- <para>
- <varname>$rule2</varname> должен содержать ключ правила для ссылок таблицы
- пересечений на целевую таблицу. В данном примере это связь между
- таблицами <code>Bugs</code> и <code>Products</code>
- </para>
- <para>
- Как и в случае использования методов для извлечения родительских и
- зависимых строк, если вы не зададите правило, то метод использует
- первое правило в массиве <varname>$_referenceMap</varname>,
- соответствующее таблицам в связи. Если нужно использовать другое
- правило, то необходимо указать ключ.
- </para>
- <para>
- В примере кода выше ключ правила не указан, поэтому по умолчанию
- используются первые подходящие правила из массива. В данном случае
- для правила <varname>$rule1</varname> будет использоваться
- <code>'Reporter'</code>, для правила <varname>$rule2</varname> -
- <code>'Product'</code>.
- </para>
- <example id="zend.db.table.relationships.fetching.many-to-many.example-by">
- <title>Извлечение строк через метод для связей "многие-ко-многим" по определенному правилу</title>
- <para>
- Этот пример демонстрирует получение объекта Row из исходной
- таблицы <code>Bugs</code> и поиск строк в целевой таблице,
- <code>Products</code>, соответствующих продуктам, к
- которым относится данная ошибка.
- </para>
- <programlisting language="php">
- <![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->find(1234);
- $bug1234 = $bugsRowset->current();
- $productsRowset = $bug1234->findManyToManyRowset('Products',
- 'BugsProducts',
- 'Bug');
- ]]>
- </programlisting>
- </example>
- <para>
- Вы можете также запрашивать строки из целевой таблицы в связи
- "многие-ко-многим", используя "магический метод".
- Zend_Db_Table_Row_Abstract вызывает метод
- <code>findManyToManyRowset('<TableClass>', '<IntersectionTableClass>', '<Rule1>', '<Rule2>')</code>, если вы вызываете метод, соотвествующий
- одному из следующих шаблонов:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <varname>$row->find<TableClass>Via<IntersectionTableClass>
- ([Zend_Db_Table_Select $select])</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>$row->find<TableClass>Via<IntersectionTableClass>By<Rule1>
- ([Zend_Db_Table_Select $select])</varname>
- </para>
- </listitem>
- <listitem>
- <para>
- <varname>$row->find<TableClass>Via<IntersectionTableClass>By<Rule1>And<Rule2>
- ([Zend_Db_Table_Select $select])</varname>
- </para>
- </listitem>
- </itemizedlist>
- <para>
- В этих шаблонах <code><TableClass></code> и
- <code><IntersectionTableClass></code> являются именами классов
- целевой таблицы и таблицы пересечений
- соответственно. <code><Rule1></code> и
- <code><Rule2></code> являются ключами правил в таблице
- пересечений, соответствующими исходной таблице и целевой таблице,
- соответственно.
- </para>
- <note>
- <para>
- Имя таблицы и ключ правила в вызовах методов должны в точности
- соответствовать написанию имени класса таблицы и ключа правила
- при объявлении.
- </para>
- </note>
- <example id="zend.db.table.relationships.fetching.many-to-many.example-magic">
- <title>Извлечение строк с использованием магического метода для связей "многие-ко-многим"</title>
- <para>
- Этот пример демонстрирует поиск в целевой таблице в связи
- "многие-ко многим" строк, соответствующих продуктам, к которым
- относится данная ошибка.
- </para>
- <programlisting language="php">
- <![CDATA[
- $bugsTable = new Bugs();
- $bugsRowset = $bugsTable->find(1234);
- $bug1234 = $bugsRowset->current();
- // Используется правило связи по умолчанию
- $products = $bug1234->findProductsViaBugsProducts();
- // Задается правило связи
- $products = $bug1234->findProductsViaBugsProductsByBug();
- ]]>
- </programlisting>
- </example>
- </sect2>
- <sect2 id="zend.db.table.relationships.cascading">
- <title>Каскадные операции записи</title>
- <note>
- <title>Объявление DRI в БД</title>
- <para>
- Объявление каскадных операций в Zend_Db_Table предназначено
- <emphasis>только</emphasis> для тех СУРБД, которые
- не поддерживают декларативной ссылочной целостности (declarative
- referential integrity - сокр. DRI).
- </para>
- <para>
- Например, если вы используете механизм хранения MyISAM в MySQL
- или SQLite, не поддерживающие DRI, то для вас может быть
- полезным объявить каскадные операции через Zend_Db_Table.
- </para>
- <para>
- Если ваша СУРБД реализует DRI и поддерживает предложения
- <code>ON DELETE</code> и <code>ON UPDATE</code>, то вам следует
- объявить эти предложения в вашей БД вместо использования
- каскадных возможностей Zend_Db_Table.
- Объявление каскадных правил DRI в СУРБД лучше в плане
- производительности, стабильности работы с БД и целостности
- данных.
- </para>
- <para>
- Тем более, не объявляйте каскадные операции
- одновременно в СУРБД и в классе Zend_Db_Table.
- </para>
- </note>
- <para>
- Вы можете объявить каскадные операции для их выполнения в зависимой
- таблице при применении операций <code>UPDATE</code> и
- <code>DELETE</code> к строкам в родительской таблице.
- </para>
- <example id="zend.db.table.relationships.cascading.example-delete">
- <title>Пример каскадного удаления</title>
- <para>
- Этот пример демонстрирует удаление строки в таблице
- <code>Products</code>, которая была сконфигурирована для
- автоматического удаления зависимых строк в таблице
- <code>Bugs</code>.
- </para>
- <programlisting language="php">
- <![CDATA[
- $productsTable = new Products();
- $productsRowset = $productsTable->find(1234);
- $product1234 = $productsRowset->current();
- $product1234->delete();
- // Автоматически выполняется каскадное
- // удаление зависимых строк в таблице Bugs
- ]]>
- </programlisting>
- </example>
- <para>
- Аналогично, если вы используете <code>UPDATE</code> для изменения
- значения первичного ключа в родительской таблице, то при этом часто
- требуется, чтобы значение внешнего ключа в зависимой таблице также
- изменялось на новое, и таким образом поддерживалась ссылочная
- целостность.
- </para>
- <para>
- Обычно нет необходимости в том, чтобы изменять значение первичного
- ключа, которое генерируется последовательностью (sequence) или
- другим механизмом. Но если вы используете <emphasis>естетственные
- ключи</emphasis>, которые иногда могут изменять свое значение, то,
- скорее всего, нужно будет использовать каскадное обновление
- зависимых таблиц.
- </para>
- <para>
- Для объявления каскадных связей в Zend_Db_Table отредактируйте
- правила в массиве <varname>$_referenceMap</varname>. Установите в
- ассоциативного массиве под ключами <code>'onDelete'</code> и
- <code>'onUpdate'</code> значение 'cascade' (или константу
- <code>self::CASCADE</code>). До того, как строка будет удалена из
- родительской таблицы или изменится значение ее первичного ключа,
- будут удалены или обновлены любые строки в зависимой таблице,
- ссылающиеся на эту строку родительской таблицы.
- </para>
- <example id="zend.db.table.relationships.cascading.example-declaration">
- <title>Пример объявления каскадных операций</title>
- <para>
- В примере ниже строки в таблице <code>Bugs</code> автоматически
- удаляются, если строка в таблице <code>Products</code>, на
- которую они ссылаются, удаляется. Элемент
- <code>'onDelete'</code> записи в массиве связей установлен в
- <code>self::CASCADE</code>.
- </para>
- <para>
- В примере ниже не выполняется каскадное обновление, если
- изменяется значение первичного ключа. Элемент
- <code>'onUpdate'</code> записи в массиве связей установлен в
- <code>self::RESTRICT</code>. Вы можете получить тот же самый
- результат, используя значение <code>self::NO_ACTION</code> или
- пропустив элемент <code>'onUpdate'</code>.
- </para>
- <programlisting language="php"><![CDATA[
- class BugsProducts extends Zend_Db_Table_Abstract
- {
- ...
- protected $_referenceMap = array(
- 'Product' => array(
- 'columns' => array('product_id'),
- 'refTableClass' => 'Products',
- 'refColumns' => array('product_id'),
- 'onDelete' => self::CASCADE,
- 'onUpdate' => self::RESTRICT
- ),
- ...
- );
- }
- ]]>
- </programlisting>
- </example>
- <sect3 id="zend.db.table.relationships.cascading.notes">
- <title>Примечания относительно каскадных операций</title>
- <para>
- <emphasis>Каскадные операции, вызываемые
- Zend_Db_Table, не являются атомарными.</emphasis>
- </para>
- <para>
- Это означает, что если ваша БД реализует ограничения ссылочной
- целостности и принуждает к их использованию, то каскадное
- обновление, выполняемое классом Zend_Db_Table, конфликтует с
- этими ограничениями и результатом будет нарушение ссылочной
- целостности.
- Вы можете использовать каскадное обновление в Zend_Db_Table
- <emphasis>только</emphasis> если когда ваша БД не принуждает к
- использованию ограничений ссылочной целостности.
- </para>
- <para>
- Каскадное удаление меньше страдает от проблем нарушения
- ссылочной целостности. Вы можете удалить зависимые строки в
- неатомарном действии до удаления родительской строки, на
- которую они ссылаются.
- </para>
- <para>
- Тем не менее, неатомарность операций изменения и удаления в
- БД приводит к тому, что есть риск того, что другой пользователь
- БД будет видеть противоречивые данные. Например, если вы удалите
- строку и все зависимые строки, то есть небольшая вероятность
- того, что другой клиент может сделать запрос к БД после того,
- как вы удалили зависимые строки, но до того, как вы удалите
- родительскую строку. Эта клиентская программа может увидеть
- родительскую строку без зависимых строк и решить, что это
- задуманное состояние данных.
- </para>
- <para>
- Проблема неатомарных измнений может быть частично решена
- использованием транзакций для изолирования ваших изменений. Но
- некоторые СУРБД не поддерживают транзакции или позволяют
- клиентам читать "грязные" изменения в БД, которые не были еще
- зафиксированы.
- </para>
- <para>
- <emphasis>Каскадные операции в Zend_Db_Table вызываются только классом Zend_Db_Table</emphasis>
- </para>
- <para>
- Каскадные операции удаления и добавления, объявленные в ваших
- классах Zend_Db_Table выполняются, если вы выполняете методы
- <code>save()</code> и <code>delete()</code> класса Row.
- Но если вы обновляете или удаляете данные, используя другой
- интерфейс, например, утилиту запросов или другое приложение, то
- каскадные операции не выполняются.
- Даже когда используются методы <code>update()</code> и
- <code>delete()</code> класса Zend_Db_Adapter, каскадные
- операции, определенные в ваших классах Zend_Db_Table, не
- выполняются.
- </para>
- <para>
- <emphasis>Не существует каскадного добавления
- <code>INSERT</code>.</emphasis>
- </para>
- <para>
- Не поддерживается каскадное добавление <code>INSERT</code>. Вы
- должны добавить строку в родительской таблице в одной операции и
- добавить строки в зависимой таблице в другой операции.
- </para>
- </sect3>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|