ODB ----+ * | * Common App DB -> DB ---+--------+-------+ * | | | * Individual tables -> Person Address State * * ******************************************************************************/ require_once('creole/Creole.php'); class ODB { // Static (globalish) vars static public $in_transaction = false; static public $singleton = false; // Class vars public $conn; public $table; public $plural; // so we can find ourselves in others' caches public $id_name = "id"; public $columns = array(); public $has_a = array(); public $has_many = array(); public $has_many_many = array(); public $col_alias = array(); // Instance vars public $currow = array(); // Holds the current row in memory public $cur_result; // Keep a query result handle for looping public $id; public $close_transaction = false; public $attribute = array(); // User-defined extra vars public $has_many_cache = array(); public $global_cache = false; public $viewType = 'ODBView'; public $view; public $searchViewType = 'ODBSearchView'; public $searchView; static function GetNew($class, $id) { if(eval("return {$class}::\$singleton;")) { if(isset($_SESSION['odb'][$class][$id])) { #error_log("Using cached version of $class - $id"); return $_SESSION['odb'][$class][$id]; } else { error_log("Caching new instance of $class - $id"); $obj = new $class; $obj->do_get($id); $_SESSION['odb'][$class][$id] = $obj; return $obj; } } else { error_log("Caching not enabled for $class ($id)"); $obj = new $class; $obj->do_get($id); return $obj; } } function autoLoad($infer_relationships = true) { $table = get_class($this); $this->table = $table; $dbinfo = $this->conn->getDatabaseInfo(); $tableInfo = $dbinfo->getTable($this->table); $this->columns = $tableInfo->getColumns(); $this->id_name = $tableInfo->getPrimaryKey()->getName(); foreach($this->columns as $key => $col) { if(get_class($col) == 'ColumnInfo') { $this->columns[$key] = $col->name; } } error_log("Key: $this->id_name"); error_log("Columns: " . var_export($this->columns, true)); // Unset the primary ID unset($this->columns[array_search($this->id_name, $this->columns)]); // TODO: This only gets has_a relationships, we want it to also do has_many // relationships too if($infer_relationships) { foreach($this->columns as $col) { $colname = $col; error_log("Looking for relationship in $table @ $colname"); $parts = explode('_', $colname); if(count($parts) > 1) { if(count($parts) == 3) { $alias = $parts[0]; $table = $parts[1]; } else { $table = $parts[0]; $alias = $table; } if(class_exists($table)) { # Remove it from the column list unset($this->columns[$colname]); $this->has_a[$alias] = array( 'table' => $table, 'key' => $table . '_id' ); } } } } } function clear() { $this->currow = array(); unset($this->cur_result); unset($this->id); } function attr($attr, $val = NULL) { if(isset($val)) { $this->attr[$attr] = $val; } return $this->attr[$attr]; } function dirty_row($id = NULL, $val = NULL) { if(!isset($id)) $id = $this->id; if(isset($val)) { $_SESSION['dirty_row'][$this->table][$id] = $val; } if(isset($_SESSION['dirty_row'])) return $_SESSION['dirty_row'][$this->table][$id]; return NULL; } function clear_dirty_row($id = NULL) { if(!isset($id)) $id = $this->id; unset($_SESSION['dirty_row'][$this->table][$id]); } function is_dirty($id = NULL) { if(!isset($id)) $id = $this->id; if(isset($_SESSION['dirty_row'][$this->table])) return array_key_exists($id, $_SESSION['dirty_row'][$this->table]); return false; } // We'll just sleep with everything function __sleep() { $members = array_keys(get_class_vars(get_class($this))); $members = array_diff($members, array("in_transaction","singleton")); $m2 = array(); foreach($members as $m) { if(isset($this->$m)) array_push($m2, $m); } $members = $m2; return $members; } function begin_transaction() { if(self::$in_transaction) { $this->close_transaction = false; } else { $this->close_transaction = true; $sql = "BEGIN;"; $stm = $this->conn->prepareStatement($sql); $stm->executeUpdate(); } } function commit_transaction() { if(self::$in_transaction && $this->close_transaction) { $this->close_transaction = false; self::$in_transaction = false; $sql = "COMMIT;"; $stm = $this->conn->prepareStatement($sql); $stm->executeUpdate(); } } function rollback_transaction() { if(self::$in_transaction) { $this->close_transaction = false; self::$in_transaction = false; $sql = "ROLLBACK;"; $stm = $this->conn->prepareStatement($sql); $stm->executeUpdate(); } } function getNonAlias($col) { if(isset($this->col_alias[$col])) $col = $this->col_alias[$col]; return $col; } // TODO: Do some checks to see if this is a valid column function get($col) { if(isset($this->col_alias[$col])) $col = $this->col_alias[$col]; if(empty($this->currow) || (!array_key_exists($col, $this->currow))) { //error_log("Column $col not found in table $this->table"); return NULL; } return $this->currow[$col]; } // TODO: Do some checks to see if this is a valid column function set($col, $val = NULL) { if(is_array($col)) { foreach($col as $colname => $colval) { $this->set($colname, $colval); } return 1; } else { if(isset($this->col_alias[$col])) $col = $this->col_alias[$col]; if(isset($this->currow[$col]) && $this->currow[$col] == $val) { return $val; } $this->currow[$col] = $val; if(isset($this->id)) { $this->dirty_row($this->id, $this->currow); } return $val; } } function get_or_set($col, $val = NULL) { if(!isset($val)) { return $this->get($col); } else { return $this->set($col, $val); } } function update_if_dirty() { if($this->is_dirty()) { error_log("Updating table " . $this->table . ", dirty record #" . $this->id); $this->update(); } } // Put our current values into the database, using either INSERT or UPDATE function update() { if(isset($this->id)) { // We have an ID, so we should update return $this->do_update(); } else { // Welp... no ID found, so lets do an insert return $this->do_insert(); } } function do_update() { // Build and execute our UPDATE query $update_list = preg_replace('/^(.*)$/','$1 = ?', array_keys($this->currow)); $update_list = implode(', ', $update_list); $sql = "UPDATE $this->table SET $update_list where $this->id_name = ?"; $stm = $this->conn->prepareStatement($sql); $stm->executeUpdate(array_merge(array_values($this->currow), array($this->id))); // We are no longer dirty! $this->clear_dirty_row(); // And then re-fetch ourselves for any other values we might've gotten // TODO: Make this optional //$this->do_get($this->id); // And we return the ID to indicate success return $this->id; } function do_insert() { // Build and execute our INSERT query $field_list = preg_replace('/^(.*)$/','$1', array_keys($this->currow)); $field_list = implode(', ', $field_list); $qmark_list = preg_replace('/^(.*)$/','?', array_keys($this->currow)); $qmark_list = implode(', ', $qmark_list); $sql = "INSERT INTO $this->table ($field_list) VALUES ($qmark_list)"; $stm = $this->conn->prepareStatement($sql); $stm->executeUpdate(array_values($this->currow)); // get the generated ID $id = $this->conn->getIdGenerator()->getId(); // And then re-fetch ourselves for any other values we might've gotten $this->clear_dirty_row(); $this->do_get($id); // And we return the ID return $id; } // Get the given ID, possibly from our stored (dirty) version function do_get($id) { if($this->is_dirty($id)) { $this->id = $id; $this->currow = $this->dirty_row($id); error_log("Found in dirty store!"); } else { error_log("I am a " . get_class($this)); error_log("Getting copy from DB for $this->table:$id"); return $this->do_nondirty_get($id); } } function trim_currow() { foreach($this->currow as $name => $val) { $this->currow[$name] = trim($val); } } // Get the ID, but definately NOT from the dirty version function do_nondirty_get($id) { $sql = "SELECT * FROM $this->table WHERE $this->id_name = ?"; $stm = $this->conn->prepareStatement($sql); $result = $stm->executeQuery(array($id)); if($result->getRecordCount() < 1) { error_log("Nothing found during do_get. SQL: $sql - ID: $id"); // Not found } else if ($result->getRecordCount() > 1) { // Too much found error_log("TOO MUCH found during do_get. SQL: $sql - ID: $id"); } else if ($result->getRecordCount() == 1) { $result->next(); $this->currow = $result->getRow(); //$this->trim_currow(); //if(!isset($this->currow[$this->id_name])) { // print("
Table: $this->table, ID: $this->id_name, SQL:$sql, ID: $id");
      //  var_dump($this->currow);
      //}
      $this->id = $this->currow[$this->id_name];
      unset($this->currow[$this->id_name]);
      return $this->id;
    }
  }

  // TODO: This does an immediate delete... should it do a pending delete and
  // then actually do the delete when an update() is issued? Probably. Oh well.
  function delete() {
    if(isset($this->id)) {
      $sql = "DELETE FROM $this->table WHERE $this->id_name = ?";
      $stm = $this->conn->prepareStatement($sql);
      $result = $stm->executeUpdate(array($this->id));
      $this->clear_dirty_row($this->id);

      # Remove from session obj cache
      unset($_SESSION['odb'][get_class($this)][$this->id]);

      # Look for ourselves in has-many relationships
      error_log("delete: looking for has_a stuff");
      foreach($this->has_a as $holder) {
        error_log("  trying {$holder['table']}");
        if(isset($holder['obj'])) {
          error_log("  I do have an obj for them...");
          $obj = $holder['obj'];
          if(isset($obj->has_many_cache[$this->plural])) {
            error_log("  Looking to delete myself from " . get_class($obj));
            $offset = array_search($this, $obj->has_many_cache[$this->plural]);
            if($offset)
              error_log("  Deleting from " . get_class($obj));
              unset($obj->has_many_cache[$this->plural][$offset]);
          }
        }
      }

      unset($this->id);
    } else {
      // TODO: Throw an exception
    }
  }

  // TODO: Implement other search types. Lets say the default is 'AND'
  //       Also consider other ways of having a more powerful search
  // This sets up an iteration, so if you just want the first one remember to check $obj->next()
  // TODO: This currently doesn't pay attention to non-inserted dirty rows
  function search($extra = "", $type = 'AND', $COMPAIR = '=') {
    $where_list = preg_replace('/^(.*)$/',"\$1 $COMPAIR ?", array_keys($this->currow));
    $where_list = implode(" $type ", $where_list);
    if($where_list == '') {
      $sql = "SELECT * FROM $this->table $extra";
    } else {
      $sql = "SELECT * FROM $this->table WHERE $where_list $extra";
    }
    $stm = $this->conn->prepareStatement($sql);
    $result = $stm->executeQuery(array_values($this->currow));
    if($result->getRecordCount() < 1) {
      // Not found
      #error_log("No records found in search. SQL: $sql; params: ("
      #  . join(',',$this->currow) . ")");
    } else {
      $this->cur_result = $result;
    }
  }

  function getSqlLink($t, $otherWay = false) {
    $table = get_class($t);
    foreach($this->has_a as $r => $v) {
      if($v['table'] == $table) {
        $k = $this->getNonAlias($v['key']);
        return "{$this->table}.{$k} = {$t->table}.{$t->id_name}";
      }
    }
    foreach($this->has_many as $r => $v) {
      if($v['table'] == $table) {
        $k = $t->getNonAlias($v['key']);
        return "{$this->table}.{$this->id_name} = {$t->table}.{$k}";
      }
    }
    if(!$otherWay) {
      return $t->getSqlLink($this, true);
    }
    return NULL;
  }

  # $objs structure:
  #   $objs = array(
  #     array($timesheetRow, 'Timesheet'),
  #     array($project, 'TimesheetRow'),
  #     array($client, 'Project'),
  #     array($employee, 'Timesheet'),
  #     array($user, 'Employee'),
  function stupidSearchSets($connections, $use_or = false) {
    $params = array();
    $sql = "
      SELECT *
        FROM $this->table
       WHERE {$this->table}.{$this->id_name} in (
             SELECT {$this->table}.{$this->id_name}
               FROM $this->table
    ";

    $where_sql = ' WHERE 1 = 1  ';
    $combine = 'AND';
    if($use_or) {
      $where_sql = ' WHERE 1=0 ';
      $combine = 'OR';
    }


    # Get baseline where restrictions
    if(!empty($this->currow)) {
      foreach($this->currow as $col => $val) {
        if($val != '') {
          //error_log("    " . $obj->table . ".$col = ? ($val)");
          if(preg_match('/^[\w\s]+$/', $val)) {
            $val = preg_replace('/\s+/', '%', $val);
            $where_sql .= "  $combine {$this->table}.{$col} like ? \n";
            $params[] = "%$val%";
          } else {
            $where_sql .= "  $combine {$this->table}.{$col} = ? \n";
            $params[] = $val;
          }
        }
      }
    }

    foreach($connections as $c) {
      list($obj, $link) = $c;
      //error_log("Obj: " . $obj->table . " - $link");
      $t = new $link;
      $sql_link = $obj->getSqlLink($t);
      $sql .= " LEFT JOIN $obj->table ON $sql_link \n";
      foreach($obj->currow as $col => $val) {
        if($val != '') {
          //error_log("    " . $obj->table . ".$col = ? ($val)");
          if(preg_match('/^[\w\s]+$/', $val)) {
            $val = preg_replace('/\s+/', '%', $val);
            $where_sql .= "  $combine {$obj->table}.{$col} like ? \n";
            $params[] = "%$val%";
          } else {
            $where_sql .= "  $combine {$obj->table}.{$col} = ? \n";
            $params[] = $val;
          }
        }
      }
    }

    $sql .= " $where_sql )";
    #error_log("SQL:\n$sql\n");
    #error_log("Params: " . var_export($params, true));

    // Lets DO IT!!! WOOOOHOOOOOO!
    error_log("Start Query");
    $stm = $this->conn->prepareStatement($sql);
    $result = $stm->executeQuery($params);
    error_log("Query Done");
    if($result->getRecordCount() < 1) {
      // Not found
      #error_log("No records found in search. SQL: $sql; params: ("
      #  . join(',',$this->currow) . ")");
    } else {
      $this->cur_result = $result;
    }
  }

  function getRecordCount() {
    if(isset($this->cur_result)) {
      return $this->cur_result->getRecordCount();
    }
    return -1;
  }

  function next() {
    if(isset($this->cur_result)) {
      $state = $this->cur_result->next();
      $this->currow = $this->cur_result->getRow();
      if(!empty($this->id_name)) {
        $this->id = $this->currow[$this->id_name];
        unset($this->currow[$this->id_name]);
      } else {
        return $state;
      }

      # If we have a non-updated version of this, use the local one
      if($this->is_dirty()) {
        $this->currow = $this->dirty_row($this->id);
      }

      return $this->id;
    } else {
      // TODO: Throw an exception or something
    }
  }

  function fetch_all() {
    $all = array();
    while($this->next()) {
      $all[] = clone($this);
    }
    return $all;
  }

  function fetch_all_has_many($method, $args = NULL) {
    if(isset($this->has_many[$method]['cache'])
       &&    $this->has_many[$method]['cache']) {

      if(isset($this->has_many_cache[$method]))
        return $this->has_many_cache[$method];
      $many = $this->search_has_many($method, $args);

      // Prepair for reverse-lookups
      $cname = get_class($this);
      $cname = substr_replace($cname, strtolower($cname{0}), 0, 1);
      if(isset($many->has_a[$cname])) {
        $many->has_a[$cname]['obj'] = $this;
      }

      $all = $many->fetch_all();
      $this->has_many_cache[$method] = $all;
      return $all;

    } else {
      $many = $this->search_has_many($method, $args);
      $all = $many->fetch_all();
      return $all;
    }
  }

  // Go through all the dirty rows for this table and look for exact matches
  function fetch_dirty() {
    $dirty = array();
    if(isset($_SESSION['dirty_row'][$this->table])) {
      foreach($_SESSION['dirty_row'][$this->table] as $id => $row) {
        $keeper = true;
        foreach($this->currow as $col => $val) {
          if($row[$col] != $val) {
            $keeper = false;
            break;
          }
        }
        if($keeper)
          $dirty[] = $id;
      }
    }
    return $dirty;
  }

  // Nice little wrapper to get the current ID
  function id($new_id = null) {
    // You probably shouldn't set the ID...
    if(isset($new_id)) {
     $this->id = $new_id;
    }
    return $this->id;
  }

  function get_or_set_has_a($col, $other_obj = NULL) {
    $key = $this->has_a[$col]['key'];
    $obj = $this->has_a[$col]['table'];
    if(isset($other_obj)) {
      if(is_string($other_obj)) {
        $this->set($key, $other_obj);
        return $other_obj;
      }

      // Add ourselves to the has_a cache if need be
      if(isset($other_obj->has_many[$this->plural]['cache'])
         &&    $other_obj->has_many[$this->plural]['cache']) {
        $other_obj->has_many_cache[$this->plural][] = $this;
        $this->has_a[$col]['obj'] = $other_obj;
      }

      $val = $other_obj->id();
      $this->set($key, $val);
      return $val;
    } else {

      // Check to see if we have this cached as a holder
      if(isset($this->has_a[$col]['obj']))
        return $this->has_a[$col]['obj'];

      // Figure out what key we are looking for
      $val = $this->get($key);

      $thing = ODB::GetNew($obj, $val);

      return $thing;
    }
  }


  function add_has_many($table, $obj) {
    #...
  }

  function search_has_many($table, $search = NULL) {
    $many = $this->has_many[$table];
    $table = $many['table'];
    $key = $many['key'];
    $obj = new $table;
    $obj->set($key, $this->id);
    call_user_func_array(array($obj, 'search'), $search);
    return $obj;
  }

  function remove_has_many($table, $obj) {
    #...
  }

  function add_has_many_many($table, $obj) {
    #...
  }

  function search_has_many_many($table, $search = NULL) {
    #...
    #$this->has_many_many = array(
    #  'groups' => array(
    #    'table' => 'Group',
    #    'table_key' => 'group_id',
    #    'connector' => 'intranet_user_group',
    #    'key' => 'user_id')
    #);

  }

  function remove_has_many_many($table, $obj) {
    #...
  }
    
  
  // The real magic
  // First we check to see if this is a joined column, if so we do a lookup
  // Then we do a get/set of the column they gave us
  function __call($method, $args) {
    $arg_zero = isset($args[0]) ? $args[0] : NULL;

    // See if this is one of our columns
    if(in_array($method, $this->columns)) {
      return $this->get_or_set($method, $arg_zero);
    }

    // Check for has-a relationship get/set
    // This will return a single instance of the other object
    if(in_array($method, array_keys($this->has_a))) {
      return $this->get_or_set_has_a($method, $arg_zero);
    }

    // Check for has-many relationship get (array)
    // This will return a single instance of the other object
    if(in_array($method, array_keys($this->has_many))) {
      return $this->fetch_all_has_many($method, $args);
    }

    if(substr($method, 0, 7) == 'search_') {
      $method = substr($method, 7);

      // Check for has-many relationship search
      // $addr_list = $person->search_addresses( ... )
      //    -->  $addr_list = $address->search(array('person_id' => $person->id(), ...));
      if(in_array($method, array_keys($this->has_many))) {
        return $this->search_has_many($method, $args);
      }

      // Check for many-to-many relationship search
      // $addr_list = $person->search_addresses( ... )
      //    -->  $addr_list = $address->search(array('person_id' => $person->id(), ...));
      if(in_array($method, array_keys($this->has_many_many))) {
        return $this->search_has_many_many($method, $args);
      }

    }

    // Check for a has-many relationship addition
    if(in_array('add_to_' . $method, array_keys($this->has_many))) {
      return $this->add_has_many($method, $args);
    }

    // Check for a has-many relationship removal
    if(in_array('remove_from_' . $method, array_keys($this->has_many))) {
      return $this->remove_has_many($method, $args);
    }


    // Check for many-to-many relationship addition
    if(in_array('add_to_' . $method, array_keys($this->has_many_many))) {
      return $this->add_has_many_many($method, $args);
    }

    // Check for a many-to-many relationship removal
    if(in_array('remove_from_' . $method, array_keys($this->has_many_many))) {
      return $this->remove_has_many_many($method, $args);
    }

    // Check to see if this is aliased as something else
    if(preg_grep("/(add_to_|remove_from_|search_)?$method/",
        array_keys($this->col_alias))) {
      if(isset($this->col_alias[$method]))
        return $this->__call($this->col_alias[$method], $args);
    }

    throw new Exception("Unknown Method $method!");
  }



  /*******************************
   ** Database-aware HTML tools **
   *******************************/

  function html_name($col) {
    if(isset($this->col_alias[$col]))
      $col = $this->col_alias[$col];
    return (get_class($this) .'['. $this->id .']['. $col . ']');
  }

  // An input form field
  function html_input($col, $extra_html = NULL) {
    if(isset($this->col_alias[$col]))
      $col = $this->col_alias[$col];
    $html_name = $this->html_name($col);
    $val = $this->get($col);
    return "";
  }

  // An textarea form field
  function html_textarea($col, $extra_html = NULL) {
    if(isset($this->col_alias[$col]))
      $col = $this->col_alias[$col];
    $html_name = $this->html_name($col);
    $val = $this->get($col);
    return "";
  }

  function html_dropdown($arg) {
    $col = $arg['col'];
    $show_col = $arg['show'][0];
    $extra_html = isset($arg['extra_html']) ? $arg['extra_html'] : NULL;
    if(isset($this->col_alias[$col]))
      $col = $this->col_alias[$col];
    $html_name = $this->html_name($col);
    $obj = $this->has_a[$col]['table'];
    $key = $this->has_a[$col]['key'];
    $thing = new $obj;
    $thing->search();
    $cur_id = $this->$col()->id();
    $html = "";
    return $html;
  }


  function html_query_val($query, $col) {
    if(isset($query[get_class($this)][$this->id][$col])) {
      return $query[get_class($this)][$this->id][$col];
    } else {
      return NULL;
    }
  }

  // Update the current row based on the most recent GET/POST
  // By default update all fields, but if we are given a list just update those
  function html_update($query, $col_list = NULL) {
    $found_update = false;
    if(!isset($col_list)) {
      $col_list = $this->columns;
    }
    foreach($col_list as $col) {
      if(isset($this->col_alias[$col]))
        $col = $this->col_alias[$col];
      $newval = $this->html_query_val($query, $col);
      if($newval != $this->$col()) {
        $this->$col($newval);
        $found_update = true;
      }
    }
    return $found_update;
  }

  function html_search_update($query, $col_list = NULL) {
    $found_update = false;
    if(!isset($col_list)) {
      $col_list = $this->columns;
    }
    foreach($col_list as $col) {
      $col = $this->getNonAlias($col);
      $newval = isset($query[get_class($this)]['search'][$col])
                    ? $query[get_class($this)]['search'][$col] : NULL;
    $fieldName = get_class($this) . "[search][$col]";
      error_log("$fieldName -- val: $newval");
      if($newval != $this->$col()) {
        $this->$col($newval);
        $found_update = true;
      }
    }
    return $found_update;
  }

  function html_search_text($col, $label) {
    $col = $this->getNonAlias($col);
    $fieldName = get_class($this) . "[search][$col]";
    $val = $this->get($col);
    $out = "
      
$label
"; return $out; } function view() { if(isset($this->view)) return $this->view; $viewType = $this->viewType; $this->view = new $viewType($this); return $this->view; } function searchView() { if(isset($this->searchView)) return $this->searchView; $viewType = $this->searchViewType; $this->searchView = new $viewType($this); return $this->searchView; } } // End of odb class function lcfirst($s) { return strtolower($s{0}) . substr($s,1); } class ODBView { public $data; // The ODB object to whom we belong function __construct($owner) { $this->data = $owner; } function html_name($col) { return (get_class($this->data) .'['. $this->data->id .']['. $col . ']'); } // An input form field function text($col, $extra_html = NULL) { $html_name = $this->html_name($col); $val = $this->data->get($col); return ""; } // An textarea form field function textarea($col, $extra_html = NULL) { $html_name = $this->html_name($col); $val = $this->data->get($col); return ""; } /* Disabled until I fix it up a bit function dropdown($arg) { $col = $arg['col']; $show_col = $arg['show'][0]; $extra_html = isset($arg['extra_html']) ? $arg['extra_html'] : NULL; if(isset($this->data->col_alias[$col])) $col = $this->col_alias[$col]; $html_name = $this->html_name($col); $obj = $this->has_a[$col]['table']; $key = $this->has_a[$col]['key']; $thing = new $obj; $thing->search(); $cur_id = $this->$col()->id(); $html = ""; return $html; } */ function query_val($query, $col) { if(isset($query[get_class($this)][$this->id][$col])) { return $query[get_class($this)][$this->id][$col]; } else { return NULL; } } // Update the current row based on the most recent GET/POST // By default update all fields, but if we are given a list just update those function update($query, $col_list = NULL) { $found_update = false; if(!isset($col_list)) { $col_list = $this->data->columns; } foreach($col_list as $col) { $newval = $this->query_val($query, $col); if($newval != $this->data->get($col)) { $this->$col($newval); $found_update = true; } } return $found_update; } } class ODBSearchView { public $data; // The ODB object to whom we belong function __construct($owner) { $this->data = $owner; } function html_name($col) { $fieldName = get_class($this->data) . "[search][$col]"; return $fieldName; } function update($query, $col_list = NULL) { $found_update = false; if(!isset($col_list)) { $col_list = $this->columns; } foreach($col_list as $col) { $newval = isset($query[get_class($this->data)]['search'][$col]) ? $query[get_class($this->data)]['search'][$col] : NULL; if($newval == '__ANY') $newval = NULL; error_log("Updating " . get_class($this->data) . " - $col - $newval"); if($newval != $this->data->get($col)) { $this->data->$col($newval); $found_update = true; } } return $found_update; } function text($col, $label = NULL) { $fieldName = $this->html_name($col); $val = $this->data->get($col); $out = "
$label
"; return $out; } // This does a drop-down on a has-a link function lookup($col, $label = NULL) { $col = $this->data->getNonAlias($col); $fieldName = $this->html_name($col); $key = $this->data->has_a[$col]['key']; $obj = $this->data->has_a[$col]['table']; error_log("Looking for $key in $obj"); $val = $this->data->get($key); //$col()->id(); $option = new $obj; $option->search(); $out = "
$label
\n"; return $out; } } ?>