* @license PHP License * @package WB * @subpackage db */ /** * Database relation table * * Generic utility datasource to load, delete and store 1:n foreign key relations. * * @version 1.1.0 * @package WB * @subpackage db */ class WBDatasource_RelationTable extends WBStdClass { /** * Table * @var WBDatasource_Table */ private $table; /** * list of known relations * @var array */ private $config = array(); /** * key of primary table * @var string */ private $primary; /** * list of current relations * @var array */ private $relations = array(); /** * Inject WBDatasource_Table * * Optionally inject table object - this prevents from creating a new one * * @param WBDatasource_Table $table */ public function setTable($table) { $this->table = $table; } /** * Set relation config for table * * Tell which table needs foreign relations and which. * * Usually the configuration comes from form definitions like: * * * * userdownloaddir
* vfsdir *
* * userorganisation
* organisation * orgkey *
*
* * This XML boils down to an array: * $config => array( * 'downloaddir' => array( * 'table' => 'article', * ), * 'downloaddir' => array( * 'table' => 'userdownloaddir', * 'foreigntable' => 'vfsdir' * ), * 'organisation' => array( * 'table' => 'userorganisation', * 'foreigntable' => 'organisation' * 'foreignprimarymap' => 'orgkey' * ), * 'tagrelation' => array( * 'table' => 'tagreference', * 'foreigntable' => 'tag', * 'namespace' => 'somestring' * ), * ); * * * @param string $table * @param array $config */ public function setConfig($table, $config) { $this->startTable(); $this->primary = $this->table->getIdentifier($table); $this->config = $config; // primary key mapping in relation table foreach ($this->config as $t => &$rel) { if (!isset($rel['foreigntable'])) { $rel['foreigntable'] = $rel['table']; } if (!isset($rel['foreignprimarymap']) || empty($rel['foreignprimarymap'])) { $rel['foreignprimarymap'] = $this->table->getIdentifier($rel['foreigntable']); } } } public function getConfig4Key($key) { if (!empty($this->config[$key])) { return $this->config[$key]; } return array(); } /** * Inject foreign keys * * Load foreign keys from table and inject into data. * Also return native relation data * * @param array $data * @return array */ public function inject(&$data) { if (empty($this->primary)) { throw new WBException_Call('Call setConfig() first!', 1, __CLASS__); } $relData = array(); foreach ($this->config as $k => $rel) { $clause = array(); $clause[] = array( 'field' => $this->primary, 'value' => $data[$this->primary] ); // namespace settings if (!empty($rel['namespace'])) { $clause[0]['field'] = 'xid'; if ('__empty' == $rel['namespace']) { $rel['namespace'] = ''; } $clause[] = array( 'field' => 'namespace', 'value' => trim($rel['namespace']) ); } $key = $rel['foreignprimarymap']; $list = $this->table->get($rel['table'], null, null, $clause); $relData[$k] = $list; $data[$k] = array(); foreach ($list as $l) { $data[$k][] = $l[$key]; } } return $relData; } /** * Extract foreign keys from data * * Find foreign key values in data array and remove items * * @param array $data */ public function extract(&$data) { if (empty($this->primary)) { throw new WBException_Call('Call setConfig() first!', 1, __CLASS__); } $this->relations = array(); foreach ($this->config as $k => $rel) { if (!isset($data[$k])) { continue; } $this->relations[$k] = array(); if (!is_array($data[$k])) { $data[$k] = trim($data[$k]); if (empty($data[$k])) { $data[$k] = array(); } else { $data[$k] = explode(',', $data[$k]); } } $this->relations[$k] = $data[$k]; unset($data[$k]); } } /** * Remove foreign keys * * Wipe out relation * * @param string $id */ public function delete($id, $extracted = false) { if ('__new' == $id) { return; } if (empty($this->primary)) { throw new WBException_Call('Call setConfig() first!', 1, __CLASS__); } foreach ($this->config as $k => $rel) { if ($extracted && !isset($this->relations[$k])) { continue; } $primary = $this->primary; $clause = array(); if (!empty($rel['namespace'])) { $primary = 'xid'; if ('__empty' == $rel['namespace']) { $rel['namespace'] = ''; } $clause[] = array( 'field' => 'namespace', 'value' => trim($rel['namespace']) ); } $clause[] = array( 'field' => $primary, 'value' => $id ); if ($rel['table'] == $rel['foreigntable']) { $save = array( $this->primary => 0 ); $this->table->save($rel['table'], null, $save, $clause); } else { $this->table->delete($rel['table'], null, null, $clause); } } } /** * Add foreign keys * * Save foreign keys to relation table. Please note, that the foreign keys need * to be extracted from data first. * * @see extract() * @param string $id */ public function add($id) { if (empty($this->primary)) { throw new WBException_Call('Call setConfig() first!', 1, __CLASS__); } foreach ($this->config as $k => $rel) { if (!isset($this->relations[$k]) || empty($this->relations[$k])) { continue; } $key = $rel['foreignprimarymap']; if ($rel['table'] == $rel['foreigntable']) { // save key in payload table $clause = array(); $clause[] = array( 'field' => $key, 'relation' => 'in', 'value' => $this->relations[$k] ); $save = array( $this->primary => $id ); $this->table->save($rel['table'], null, $save, $clause); } else { // save in relation table $save = array(); $p = $this->primary; if (!empty($rel['namespace'])) { $p = 'xid'; } $s = array( $p => $id, $key => '' ); if (!empty($rel['namespace'])) { if ('__empty' == $rel['namespace']) { $rel['namespace'] = ''; } $s['namespace'] = $rel['namespace']; } foreach ($this->relations[$k] as $v) { $s[$key] = $v; $save[] = $s; } $this->table->save($rel['table'], '__new', $save); } } } /** * Start table * * If not injected, instantiate WBDatasource_Table */ private function startTable() { if ($this->table) { return; } $this->table = WBClass::create('WBDatasource_Table'); } }