public function setBehaviour($behaviour) { if (!in_array($behaviour, array('ignore', 'cascade'))) { throw $this->exception('Unknonw join behaviour')->addMoreInfo('behaviour', $behaviour)->addMoreInfo('supported', array('ignore', 'cascade')); } $this->model->addHook('beforeInsert', array($this, 'insertInForeingTable')); $this->model->addHook('beforeUpdate', array($this, 'updateInForeingTable')); $this->model->addHook('afterDelete', array($this, 'deleteInForeignTable')); $this->behaviour = $behaviour; return $this; }
public function set($foreign_table, $master_field = null, $join_kind = null, $relation = null) { // http://dev.mysql.com/doc/refman/5.0/en/join.html $join_types = array('left', 'right', 'inner', 'cross', 'natural', 'left outer', 'right outer', 'natural left', 'natural right', 'natural left outer', 'natural right outer'); if ($join_kind && !in_array(strtolower($join_kind), $join_types)) { throw $this->exception('Specify reasonable SQL join type.')->addMoreInfo('Specified', $join_kind)->addMoreInfo('Allowed', implode(', ', $join_types)); } $this->relation = $relation; // Split and deduce fields list($f1, $f2) = explode('.', $foreign_table, 2); $m1 = $m2 = null; if (is_object($master_field)) { $this->expr = $master_field; } else { $m1 = $this->relation ?: $this->owner; $m1 = $m1->table_alias ?: $m1->table; // Split and deduce primary table $m2 = $master_field; // Identify fields we use for joins if (is_null($f2) && is_null($m2)) { $m2 = $f1 . '_id'; } if (is_null($m2)) { $m2 = $this->owner->id_field; } $this->f1 = $f1; $this->m1 = $m1; $this->m2 = $m2; } if (is_null($f2)) { $f2 = 'id'; } $this->f2 = $f2; $this->t = $join_kind ?: 'inner'; $this->fa = $this->short_name; // Use the real ID field as defined by the model as default $this->owner->_dsql()->join($foreign_table, $this->expr ?: $m1 . '.' . $m2, $this->t, $this->short_name); // If our ID field is NOT used, must insert record in OTHER table first and use their primary value in OUR field if ($this->m2 && $this->m2 != $this->owner->id_field) { // user.contactinfo_id = contactinfo.id $this->owner->addHook('beforeInsert', array($this, 'beforeInsert'), array(), -5); $this->owner->addHook('beforeModify', array($this, 'beforeModify'), array(), -5); $this->owner->addHook('afterDelete', array($this, 'afterDelete'), array(), -5); } elseif ($this->m2) { // author.id = book.author_id $this->owner->addHook('afterInsert', array($this, 'afterInsert')); $this->owner->addHook('beforeModify', array($this, 'beforeModify')); $this->owner->addHook('beforeDelete', array($this, 'beforeDelete')); } // else $m2 is not set, expression is used, so don't try to do anything unnecessary $this->owner->addHook('beforeSave', array($this, 'beforeSave')); $this->owner->addHook('beforeLoad', array($this, 'beforeLoad')); $this->owner->addHook('afterLoad', array($this, 'afterLoad')); return $this; }
/** * Supplies a list data for multi-value fields (selects, radio buttons, * checkbox area, autocomplete). You may also use enum(). This setting * is typically used with a static falues (Male / Female), if your field * values could be described through a different model, use setModel() * or better yet - hasOne(). * * @param array $t Array( id => val ) * * @return array|$this current value if $t=UNDEFINED */ public function listData($t = UNDEFINED) { if ($this->type() === 'boolean' && $t !== UNDEFINED) { $this->owner->addHook('afterLoad,afterUpdate,afterInsert', function ($m) use($t) { // Normalize boolean data $val = !array_search($m->data[$this->short_name], $t); if ($val === false) { return; } // do nothing $m->data[$this->short_name] = (bool) $val; }); $this->owner->addHook('beforeUpdate,beforeInsert', function ($m, &$data) use($t) { // De-Normalize boolean data $val = (int) (!$m->get($this->short_name)); if (!isset($t[$val])) { return; } // do nothing $data->set($this->short_name, $t[$val]); }); } return $this->setterGetter('listData', $t); }