From 8ec4e59bb0ddac89f36dcb48ee3f14c737e6e80f Mon Sep 17 00:00:00 2001 From: Filipp Lepalaan Date: Fri, 21 May 2010 21:42:39 +0300 Subject: Fixes --- App.php | 313 ---------------------------------------- Controller.php | 415 ----------------------------------------------------- Db.php | 119 --------------- MainApp.php | 303 ++++++++++++++++++++++++++++++++++++++ MainController.php | 411 ++++++++++++++++++++++++++++++++++++++++++++++++++++ MainDb.php | 116 +++++++++++++++ MainView.php | 67 +++++++++ README | 31 ++-- View.php | 68 --------- 9 files changed, 916 insertions(+), 927 deletions(-) delete mode 100644 App.php delete mode 100644 Controller.php delete mode 100644 Db.php create mode 100644 MainApp.php create mode 100644 MainController.php create mode 100644 MainDb.php create mode 100644 MainView.php delete mode 100644 View.php diff --git a/App.php b/App.php deleted file mode 100644 index 9e59c4c..0000000 --- a/App.php +++ /dev/null @@ -1,313 +0,0 @@ - -// @copyright (c) 2009 Filipp Lepalaan -class App -{ - //// - // Fire up the application - static public function init() - { - self::log($_SERVER); - // Set custom error handler - set_error_handler('App::error_handler'); - // Set correct timezone - date_default_timezone_set(self::conf('app.timezone')); - - @list($controller, $param, $action) = App::url(); - - // No action given, read default one - if (empty($param)) { - $action = self::conf('defaults.action'); - } - - // No controller given, read default one - if (!$controller) { - $controller = self::conf('defaults.controller'); - } - - // Fire up the output buffer - ob_start(); - - // Dispatch correct controller - $c = new $controller; - - // Assume no method name was given, try $param, then default to defaultAction - // controller/param/action - if (method_exists($c, $action)) { - return $c->$action($c); - } - - // controller/action - if (method_exists($c, $param)) { - return $c->$param($c); - } - - // controller/param - if (method_exists($c, $c->defaultAction)) { - $action = $c->defaultAction; - return $c->$action($c); - } - - App::error("{$controller}_{$action}: no such method"); - - ob_end_flush(); - - } - - //// - // Requests should always be in the form: controller/action/parameters.type - // Strip type info since it's not needed at this point - static function url($index = null) - { - $url = parse_url($_SERVER['REQUEST_URI']); - if ($index == 'query') { - return $url['query']; - } - $req = ltrim($url['path'], '/'); - $array = explode('/', preg_replace('/\.\w+$/', '', $req)); - return (is_numeric($index)) ? $array[$index] : $array; - } - - /** - * - */ - static function param() - { - $url = App::url(); - return $url[1]; - } - - //// - // Return configuration data from ini file - static function conf($key = null) - { - $cpath = realpath('../system/config.ini'); - $config = parse_ini_file($cpath, true); - $config = $config['development']; - - if ($key && ! $config[$key]) { - return self::error("No such config key: $key"); - } - - return ($key) ? $config[$key] : $config; - - } - - static function type() - { - $tokens = explode('/', $_SERVER['REQUEST_URI']); - $last = array_pop($tokens); - $type = ltrim(strrchr($last, '.'), '.'); - - $contentTypes = array('html', 'rss', 'xml', 'tpl', 'pdf', 'jpg'); - - if (in_array($type, $contentTypes)) { - return $type; - } - - return 'html'; - - } - - static function ok($msg) - { - $ok = array('result' => 'ok', 'msg' => $msg); - self::json($ok); - } - - static function error($msg) - { - $err = array('result' => 'error', 'msg' => $msg); - // And log it locally - self::log($msg); - } - - static function json($msg) - { - $json = json_encode($msg); - header('Content-Type: application/json'); - header('Content-Length: ' . mb_strlen($json)); - print $json; - } - - //// - // Log an error to our own logging system - static function log($msg) - { - if (is_array($msg)) { - $msg = print_r($msg, true); - } - - $file = self::conf('app.error_log'); - - if (!is_file($file)) { - return false; - } - - $msg = trim($msg); - $fh = fopen($file, 'a+'); - fwrite($fh, trim($msg) . "\n"); - fclose($fh); - - } - - //// - // Set our own PHP error handler - static function error_handler($errno, $errstr, $errfile, $errline) - { - $str = sprintf("%s\t%s\t%s\t%s\n", date('d.m H:i:s'), - basename($errfile), $errline, $errstr - ); - - self::log($str); - - } - - //// - // Do a proper HTTP redirect - // @param string [$where] URL to redirect to - // @return void - static function redirect($url = null) - { - if (!$url) { - // Is it smart to redirect back to the page which redirected here? - $url = $_SERVER['HTTP_REFERER']; - } - header('HTTP/1.1 303 See Other'); - header('Location: ' . $url); - } - - //// - // Determine locale from USER_AGENT - static function locale() - { - if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { - return false; - } - // Set language to whatever the browser is set to - list($loc, $lang) = explode('-', $_SERVER['HTTP_ACCEPT_LANGUAGE']); - return sprintf('%s_%s', $loc, strtoupper($lang)); - } - - public function delete($table, $where) - { - if (empty($where)) { - exit(App::error('Delete without parameters')); - } - - list($key, $value) = each($where); - $sql = "DELETE FROM `$table` WHERE $key = :{$key}"; - - self::log($sql); - self::query($sql, $where); - - } - - //// - // Insert something in the database - static function insert($table, $data) - { - if (empty($data)) { - exit(self::error('Empty insert')); - } - - $cols = array(); - $vals = array(); - - foreach ($data as $k => $v) { - $cols[] = "`{$k}`"; - $vals[] = ":{$k}"; - } - - $cols = implode(',', $cols); - $vals = implode(',', $vals); - $sql = "INSERT INTO `$table` ($cols) VALUES ($vals)"; - - self::log($sql); - self::query($sql, $data); - - } - - // Move this back to Controller once PHP 5.3 is out (get_called_class()) - static function select($table, $where = 1, $what = '*', $order_by = '') - { - $out = array(); - - $query = "?"; - $values = array(1); - - if (is_array($where)) { - $values = array(); - foreach ($where as $k => $v) { - $keys[] = "`$k` = :{$k}"; - $values[":{$k}"] = $v; - } - $query = implode(" AND ", $keys); - } - - if (!empty($order_by)) { - list($ob_col, $ob_dir) = explode(" ", $order_by); - $order_by = "ORDER BY `$ob_col` $ob_dir"; - } - - $sql = "SELECT $what FROM `$table` WHERE $query $order_by"; - - self::log($sql); - self::log($values); - - $stmt = self::db()->prepare($sql); - $stmt->execute($values); - - foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { - $out[] = $row; - } - - if (count($out) == 1 && $what != "*") { - return $out[0][$what]; - } - - return $out; - - } - - //// - // Prompt for HTTP authentication - // @param string [$callback] Function that makes the actual authentication - // @param string [$realm] Realm name - // @return mixed false if cancelled or output of $function - static function auth($callback, $realm = 'Default') - { - if (!isset($_SERVER['PHP_AUTH_USER'])) - { - header(sprintf('WWW-Authenticate: Basic realm="%s"', $realm)); - header('HTTP/1.0 401 Unauthorized'); - return false; - } else { - return call_user_func($callback, $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); - } - } - - //// - // Output a JavaScript fragment - public function js($string) - { - header('Content-Type: text/javascript'); - print ''; - } - -} - - function __autoload($class_name) - { - $class_name = ucfirst($class_name); - include_once "{$class_name}.php"; - if (!class_exists($class_name)) { - exit(App::error("{$class_name}: no such class")); - } - } - -?> \ No newline at end of file diff --git a/Controller.php b/Controller.php deleted file mode 100644 index 2534397..0000000 --- a/Controller.php +++ /dev/null @@ -1,415 +0,0 @@ -class = get_class($this); - $this->table = eval("return {$this->class}::TableName;"); - - $this->view = new MainView(); - - // Table name not defined, default to class name - if (!$this->table) { - $this->table = strtolower($this->class); - } - - $this->result = null; - - if ($id) { - return $this->get($id); - } - - return $this; - - } - - /** - * Get One Thing - */ - public function get($where) - { - if (!is_array($where)) { - $where = array('id' => $where); - } - - $this->find($where); - return current($this->data); - - } - - public function db() - { - return Db::getInstance(); - } - - /** - * The New Find - */ - public function find($where = null, $sort = false, $limit = false) - { - $select = "*"; $q = ""; - - // Allow custom queries - if (is_array($where)) - { - foreach ($where as $k => $v) - { - $values[] = $v; - $args = explode(" ", $k); - $col = array_shift($args); - $op = implode(" ", $args); - - // No column name given, default to "id" - if (empty($col)) { - $col = "id"; - } - - // No operator given, default to "=" - if (empty($op)) { - $op = "="; - } - - $tmp = (empty($q)) ? ' WHERE ' : ' AND '; - $q .= $tmp . "`{$col}`" . ' ' . $op . ' ?'; - - } - } else { - $q = "WHERE `{$this->table}`.`id` = ?"; - $values = array($where); - } - - if ($where == null) { - $q = "WHERE ?"; - $values = array(1); - } - -// $schema = App::conf('tables'); -// $this->schema = $schema[$this->table]; - - // Ugly hack until PHP 5.3 - $i_sort = eval("return {$this->class}::OrderBy;"); - $i_fk = eval("return {$this->class}::ForeignKey;"); - $i_mtm = eval("return {$this->class}::ManyToMany;"); - $i_select = eval("return {$this->class}::TableSelect;"); - -// $orderBy = ($sort) ? $sort : - - if ($sort) { - list($col, $dir) = explode(' ', $sort); - $sort = "ORDER BY `{$this->table}`.`$col` $dir"; - } - - if (!$sort && $i_sort) { - $sort = "ORDER BY `{$this->table}`.{$i_sort}"; - } - - if ($i_select) { - list($select_col, $args) = explode(",", $i_select); - $select .= ", $args AS `{$select_col}`"; - } - - $sql = "SELECT $select FROM `{$this->table}` $q $sort"; - - if ($limit) { - $sql .= " LIMIT $limit"; - } - - $result = Db::fetch($sql, $values); - - if (empty($result)) { - $this->data = false; - return; - } - - for ($i=0; $i < count($result); $i++) - { - $row = $result[$i]; - $this->data[$i] = $row; - $this->find_parent($row, $i); -// $this->find_children($row, $i); - } - - return $this; - - } - - /** - * Find all child rows for this row - * @return void - */ - private function find_children($row, $i) - { - $id = $row['id']; // ID of the parent - $fk = explode(",", eval("return $this->class::HasMany;")); - - if (empty($fk[0])) { - return false; - } - - foreach ($fk as $child) - { - $sql = "SELECT * FROM `$child` WHERE `{$this->table}_id` = ?"; - - $ref_schema = App::conf('tables'); - $ref_schema = $ref_schema[$child]; - - if (@in_array($this->table, $ref_schema['belongsToMany'])) // m/n - { - $sql = "SELECT `{$child}`.*, `{$child}_{$this->table}`.*, - `{$child}_{$this->table}`.id AS {$child}_{$this->table}_id, - `{$child}`.* - FROM `{$child}_{$this->table}`, `{$this->table}`, `$child` - WHERE `{$child}_{$this->table}`.`{$this->table}_id` = `$this->table`.id AND - `{$child}_{$this->table}`.`{$child}_id` = `$child`.id AND - `{$this->table}`.id = ? - ORDER BY `{$child}`.{$ref_schema['orderBy']}"; - } else if (@in_array ($table, $ref_schema['belongsTo'])) { // 1/m - $sql = "SELECT * FROM `$ref` WHERE `$ref`.`{$table}_id` = ?"; - } - - $stmt = DB::query($sql, array($id)); - $this->data[$i][$child] = $stmt->fetchAll(PDO::FETCH_ASSOC); - - } - } - - /** - * Find all rows for this row - */ - private function find_parent($row, $i) - { - $select = "*"; - $fk = explode(",", eval("return {$this->class}::ForeignKey;")); - - // No parents defined - if (empty($fk[0])) { - return false; - } - - foreach ($fk as $parent) - { - $fkey = 'id'; - $lkey = "{$parent}_id"; - /* - if ($this->schema['foreignKey'][$parent]) - { - list($lkey, $fkey) = explode("|", $this->schema['foreignKey'][$parent]); - } - */ - $parent_id = $row[$lkey]; - -// $ref_schema = App::conf('tables'); -// $ref_schema = $ref_schema[$parent]; - $ref_schema = $fk['']; - - if ($ref_schema['select']) - { - foreach ($ref_schema['select'] as $a => $b) - { - $select .= ", $b AS `{$a}`"; - } - } - - $sql = "SELECT $select FROM `{$parent}` WHERE `{$fkey}` = ?"; - - $stmt = DB::query($sql, array($parent_id)); - $this->data[$i][$parent] = $stmt->fetchAll(PDO::FETCH_ASSOC); - - } - - } - - private function find_parents() - { - - } - - /** - * Insert this thing in the DB and return inserted - * Thing - */ - public function insert($data) - { - if (empty($data)) { - return App::error('Cannot insert emptiness'); - } - - $insert = ''; - $values = array(); - - foreach($data as $k => $v) - { - $insert .= "`{$k}`, "; - $values[":{$k}"] = $v; - } - - $insert = rtrim($insert, ', '); - $val = implode(', ', array_keys($values)); - $sql = "INSERT INTO `{$this->table}` ({$insert}) VALUES ({$val})"; - - return DB::query($sql, $values); - - } - - /** - * Delete This Thing - */ - protected function delete($where, $limit = '') - { - if (empty($where)) { - return App::error('Cannot delete without arguments'); - } - - list($key, $value) = each($where); - - if ($limit) { - $limit = " LIMIT $limit"; - } - - $data = array(":{$key}" => $value); - $sql = "DELETE FROM `{$this->table}` WHERE `{$key}` = :{$key} $limit"; - - return Db::query($sql, $data); - - } - - /** - * Update this Thing - * We keep this in the Controller since it might know - * more about the topmost class - */ - protected function update($data, $where = null) - { - if (!is_array($data)) { - return App::error('Cannot update without parameters'); - } - - if (empty($where)) { - $where = array('id' => 'id'); - } - - $query = ""; $values = array(); - list($col, $val) = each($where); - - if (!isset($data[$col])) { - $data = array_merge($data, $where); - } - - foreach ($data as $k => $v) { - $query .= "`$k` = :$k, "; - $values[":{$k}"] = $v; - } - - $query = rtrim($query, ", "); - $sql = "UPDATE `{$this->table}` SET $query WHERE `$col` = :$col"; - - return Db::query($sql, $values); - - } - - /** - * Render a view - */ - public function render($data = null, $view = null) - { - // Default to the same view as the method - if (!$view) { - $bt = debug_backtrace(); - $view = $bt[1]['function']; - } - - if (!$view) { - $view = $this->defaultAction; - } - - if (!$data) { - $data = $this->view; - } - - $type = App::type(); - // @very temporary hack? - $tpl = (App::url(0) == "admin") ? "admin" : "default"; - $template = "../system/views/{$tpl}.{$type}"; - $file = "../system/views/{$this->table}/{$view}.{$type}"; - - if (!is_file($file)) { - return App::error("{$this->table}_{$view}_{$type}: no such view"); - } - - if ($data) { - foreach ($data as $k => $v) { - $$k = $v; - } - } - - // Capture view - ob_start(); - include $file; - $view_contents = ob_get_contents(); - ob_end_clean(); - - // Capture template - ob_start(); - include $template; - $tpl_contents = ob_get_contents(); - ob_end_clean(); - - $title = ($this->pageTitle) ? $this->pageTitle : App::conf("defaults.title"); - $tpl_contents = preg_replace( - '/.*?<\/title>/', "<title>{$title}", $tpl_contents - ); - - echo str_replace('%%page_content%%', $view_contents, $tpl_contents); - - } - - public function match($cols, $match) - { - foreach ($cols as $col) { - $sql .= "`{$col}`,"; - } - - $sql = rtrim($sql, ","); - $sql = "SELECT * FROM `{$this->table}` WHERE MATCH($sql) AGAINST('{$match}')"; - - return App::db()->query($sql); - - } - - /** - * Insert or update - */ - public function upsert($data, $where = null) - { - if(!$this->get($where)) { - $out = $this->insert($data); - } else { - $out = $this->update($data, $where); - } -// App::log($out); - return $out; - - } - -} - -?> diff --git a/Db.php b/Db.php deleted file mode 100644 index f09cd85..0000000 --- a/Db.php +++ /dev/null @@ -1,119 +0,0 @@ - - * http://www.php.net/manual/en/language.oop5.patterns.php - */ - -class Db -{ - private static $instance = NULL; - - private function __construct() - { - - } - - /** - * Open persistent connection to database - */ - public static function getInstance() - { - $c = App::conf(); - - if (!self::$instance) - { - try { - self::$instance = new PDO( - "{$c['db.driver']}:host={$c['db.host']};dbname={$c['db.name']}", - $c['db.username'], $c['db.password'], array(PDO::ATTR_PERSISTENT => true) - ); - - self::$instance->query("SET NAMES utf8"); - - } catch (PDOException $e) { - exit(App::error($e->getMessage())); - } - - } - - return self::$instance; - - } - - /** - * Deny cloning - */ - public function __clone() - { - trigger_error("Cloning not work is", E_USER_ERROR); - } - - /** - * Execute an SQL query - * @return mixed - */ - public static function query($sql, $data = null) - { - if (!$data) { - $data = array(); - } - - // Might be just a string - if (!is_array($data)) { - $data = array($data); - } - - try { - - $pdo = self::getInstance(); - $stmt = $pdo->prepare($sql); - $result = $stmt->execute($data); - - if (!$result) { - list($ec, $dec, $emsg) = $pdo->errorInfo(); - $error = $emsg ."\n" . print_r(debug_backtrace(), true); - return App::error($error); - } - - } catch (PDOException $e) { - $error = $e->getMessage() . $sql; - $error .= "\n" . print_r(debug_backtrace(), true); - return App::error($error); - } - - // Select statements need the query results - if (preg_match('/^SELECT/i', $sql)) { - return $stmt; - } - - if (empty($data['id'])) { - $data['id'] = $pdo->lastInsertId(); - } - - $out = array(); - - // Always strip ":" prefixes from input array keys - foreach ($data as $k => $v) { - $key = ltrim($k, ':'); - $out[$key] = $v; - } - - return $out; - - } - - /** - * - */ - public static function fetch($sql, $data = null) - { - $stmt = self::query($sql, $data) - or exit(App::error("Error executing query $sql")); - return $stmt->fetchAll(PDO::FETCH_ASSOC); - } - -} - -?> \ No newline at end of file diff --git a/MainApp.php b/MainApp.php new file mode 100644 index 0000000..e55a74a --- /dev/null +++ b/MainApp.php @@ -0,0 +1,303 @@ + +// @copyright (c) 2009 Filipp Lepalaan +class MainApp +{ + //// + // Fire up the application + static public function init() + { + @list($controller, $param, $action) = App::url(); + + // no action given, read default one + if (empty($param)) { + $action = self::conf('defaults.action'); + } + + // no controller given, read default one + if (!$controller) { + $controller = self::conf('defaults.controller'); + } + + // fire up the output buffer + ob_start(); + + // Dispatch correct controller + $c = new $controller; + + // Assume no method name was given, try $param, then default to defaultAction + // controller/param/action + if (method_exists($c, $action)) { + return $c->$action($c); + } + + // controller/action + if (method_exists($c, $param)) { + return $c->$param($c); + } + + // controller/param + if (method_exists($c, $c->defaultAction)) { + $action = $c->defaultAction; + return $c->$action($c); + } + + App::error("{$controller}_{$action}: no such method"); + + ob_end_flush(); + + } + + //// + // Requests should always be in the form: controller/action/parameters.type + // Strip type info since it's not needed at this point + static function url($index = null) + { + $url = parse_url($_SERVER['REQUEST_URI']); + + if ($index == 'query') { + return $url['query']; + } + $req = ltrim($url['path'], '/'); + $array = explode('/', preg_replace('/\.\w+$/', '', $req)); + return (is_numeric($index)) ? $array[$index] : $array; + } + + //// + // return parameter part of URL + static function param() + { + $url = App::url(); + return $url[1]; + } + + //// + // get configuration data from ini file + static function conf($key = NULL) + { + $cpath = realpath('../system/config.ini'); + + if (!file_exists($cpath)) { + trigger_error('Failed to open config file', E_USER_ERROR); + exit(); + } + + $config = parse_ini_file($cpath, true); + $config = $config['development']; + + if ($key && ! $config[$key]) { + return self::error('No such config key: '.$key); + } + + return ($key) ? $config[$key] : $config; + + } + + //// + // determine template type of request + static function type() + { + $tokens = explode('/', $_SERVER['REQUEST_URI']); + $last = array_pop($tokens); + $type = ltrim(strrchr($last, '.'), '.'); + + $contentTypes = array('html', 'rss', 'xml', 'tpl', 'pdf', 'jpg'); + + if (in_array($type, $contentTypes)) { + return $type; + } + + return 'html'; + + } + + static function ok($msg) + { + $ok = array('result' => 'ok', 'msg' => $msg); + self::json($ok); + } + + static function error($msg) + { + $err = array('result' => 'error', 'msg' => $msg); + // And log it locally + self::log($msg); + } + + static function json($msg) + { + $json = json_encode($msg); + header('Content-Type: application/json'); + header('Content-Length: ' . mb_strlen($json)); + print $json; + } + + //// + // log an error to our own logging system + static function log($msg) + { + if (is_array($msg)) { + $msg = print_r($msg, true); + } + + $file = self::conf('app.error_log'); + + if (!is_file($file)) { + return false; + } + + $msg = trim($msg); + $fh = fopen($file, 'a+'); + fwrite($fh, trim($msg) . "\n"); + fclose($fh); + + } + + //// + // do a proper HTTP redirect + // @param string [$where] URL to redirect to + // @return void + static function redirect($url = null) + { + if (!$url) { + // Is it smart to redirect back to the page which redirected here? + $url = $_SERVER['HTTP_REFERER']; + } + header('HTTP/1.1 303 See Other'); + header('Location: ' . $url); + } + + //// + // determine locale from USER_AGENT + static function locale() + { + if (!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { + return NULL; + } + // Set language to whatever the browser is set to + list($loc, $lang) = explode('-', $_SERVER['HTTP_ACCEPT_LANGUAGE']); + return sprintf('%s_%s', $loc, strtoupper($lang)); + } + + public function delete($table, $where) + { + if (empty($where)) { + exit(App::error('Delete without parameters')); + } + + list($key, $value) = each($where); + $sql = "DELETE FROM `$table` WHERE $key = :{$key}"; + + self::log($sql); + self::query($sql, $where); + + } + + //// + // insert something in the database + static function insert($table, $data) + { + if (empty($data)) { + exit(self::error('Empty insert')); + } + + $cols = array(); + $vals = array(); + + foreach ($data as $k => $v) { + $cols[] = "`{$k}`"; + $vals[] = ":{$k}"; + } + + $cols = implode(',', $cols); + $vals = implode(',', $vals); + $sql = "INSERT INTO `$table` ($cols) VALUES ($vals)"; + + self::log($sql); + self::query($sql, $data); + + } + + // Move this back to Controller once PHP 5.3 is out (get_called_class()) + static function select($table, $where = 1, $what = '*', $order_by = '') + { + $out = array(); + + $query = '?'; + $values = array(1); + + if (is_array($where)) { + $values = array(); + foreach ($where as $k => $v) { + $keys[] = "`$k` = :{$k}"; + $values[":{$k}"] = $v; + } + $query = implode(" AND ", $keys); + } + + if (!empty($order_by)) { + list($ob_col, $ob_dir) = explode(" ", $order_by); + $order_by = "ORDER BY `$ob_col` $ob_dir"; + } + + $sql = "SELECT $what FROM `$table` WHERE $query $order_by"; + + self::log($sql); + self::log($values); + + $stmt = self::db()->prepare($sql); + $stmt->execute($values); + + foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { + $out[] = $row; + } + + if (count($out) == 1 && $what != '*') { + return $out[0][$what]; + } + + return $out; + + } + + //// + // Prompt for HTTP authentication + // @param string [$callback] Function that makes the actual authentication + // @param string [$realm] Realm name + // @return mixed false if cancelled or output of $function + static function auth($callback, $realm = 'Default') + { + if (!isset($_SERVER['PHP_AUTH_USER'])) + { + header(sprintf('WWW-Authenticate: Basic realm="%s"', $realm)); + header('HTTP/1.0 401 Unauthorized'); + return false; + } else { + return call_user_func($callback, $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']); + } + } + + //// + // Output a JavaScript fragment + public function js($string) + { + header('Content-Type: text/javascript'); + print ''; + } + +} + + function __autoload($class_name) + { + $class_name = ucfirst($class_name); + include_once "{$class_name}.php"; + if (!class_exists($class_name)) { + exit(App::error("{$class_name}: no such class")); + } + } + +?> \ No newline at end of file diff --git a/MainController.php b/MainController.php new file mode 100644 index 0000000..e1545b7 --- /dev/null +++ b/MainController.php @@ -0,0 +1,411 @@ +class = get_class($this); + $this->table = eval("return {$this->class}::TableName;"); + + $this->view = new MainView(); + + // Table name not defined, default to class name + if (!$this->table) { + $this->table = strtolower($this->class); + } + + $this->result = null; + + if ($id) { + return $this->get($id); + } + + return $this; + + } + + /** + * Get One Thing + */ + public function get($where) + { + if (!is_array($where)) { + $where = array('id' => $where); + } + + $this->find($where); + return current($this->data); + + } + + public function db() + { + return Db::getInstance(); + } + + /** + * The New Find + */ + public function find($where = null, $sort = false, $limit = false) + { + $select = "*"; $q = ""; + + // Allow custom queries + if (is_array($where)) + { + foreach ($where as $k => $v) + { + $values[] = $v; + $args = explode(" ", $k); + $col = array_shift($args); + $op = implode(" ", $args); + + // No column name given, default to "id" + if (empty($col)) { + $col = "id"; + } + + // No operator given, default to "=" + if (empty($op)) { + $op = "="; + } + + $tmp = (empty($q)) ? ' WHERE ' : ' AND '; + $q .= $tmp . "`{$col}`" . ' ' . $op . ' ?'; + + } + } else { + $q = "WHERE `{$this->table}`.`id` = ?"; + $values = array($where); + } + + if ($where == null) { + $q = "WHERE ?"; + $values = array(1); + } + +// $schema = App::conf('tables'); +// $this->schema = $schema[$this->table]; + + // Ugly hack until PHP 5.3 + $i_sort = eval("return {$this->class}::OrderBy;"); + $i_fk = eval("return {$this->class}::ForeignKey;"); + $i_mtm = eval("return {$this->class}::ManyToMany;"); + $i_select = eval("return {$this->class}::TableSelect;"); + +// $orderBy = ($sort) ? $sort : + + if ($sort) { + list($col, $dir) = explode(' ', $sort); + $sort = "ORDER BY `{$this->table}`.`$col` $dir"; + } + + if (!$sort && $i_sort) { + $sort = "ORDER BY `{$this->table}`.{$i_sort}"; + } + + if ($i_select) { + list($select_col, $args) = explode(",", $i_select); + $select .= ", $args AS `{$select_col}`"; + } + + $sql = "SELECT $select FROM `{$this->table}` $q $sort"; + + if ($limit) { + $sql .= " LIMIT $limit"; + } + + $result = Db::fetch($sql, $values); + + if (empty($result)) { + $this->data = false; + return; + } + + for ($i=0; $i < count($result); $i++) + { + $row = $result[$i]; + $this->data[$i] = $row; + $this->find_parent($row, $i); +// $this->find_children($row, $i); + } + + return $this; + + } + + /** + * Find all child rows for this row + * @return void + */ + private function find_children($row, $i) + { + $id = $row['id']; // ID of the parent + $fk = explode(",", eval("return $this->class::HasMany;")); + + if (empty($fk[0])) { + return false; + } + + foreach ($fk as $child) + { + $sql = "SELECT * FROM `$child` WHERE `{$this->table}_id` = ?"; + + $ref_schema = App::conf('tables'); + $ref_schema = $ref_schema[$child]; + + if (@in_array($this->table, $ref_schema['belongsToMany'])) // m/n + { + $sql = "SELECT `{$child}`.*, `{$child}_{$this->table}`.*, + `{$child}_{$this->table}`.id AS {$child}_{$this->table}_id, + `{$child}`.* + FROM `{$child}_{$this->table}`, `{$this->table}`, `$child` + WHERE `{$child}_{$this->table}`.`{$this->table}_id` = `$this->table`.id AND + `{$child}_{$this->table}`.`{$child}_id` = `$child`.id AND + `{$this->table}`.id = ? + ORDER BY `{$child}`.{$ref_schema['orderBy']}"; + } else if (@in_array ($table, $ref_schema['belongsTo'])) { // 1/m + $sql = "SELECT * FROM `$ref` WHERE `$ref`.`{$table}_id` = ?"; + } + + $stmt = DB::query($sql, array($id)); + $this->data[$i][$child] = $stmt->fetchAll(PDO::FETCH_ASSOC); + + } + } + + /** + * Find all rows for this row + */ + private function find_parent($row, $i) + { + $select = "*"; + $fk = explode(",", eval("return {$this->class}::ForeignKey;")); + + // No parents defined + if (empty($fk[0])) { + return false; + } + + foreach ($fk as $parent) + { + $fkey = 'id'; + $lkey = "{$parent}_id"; + /* + if ($this->schema['foreignKey'][$parent]) + { + list($lkey, $fkey) = explode("|", $this->schema['foreignKey'][$parent]); + } + */ + $parent_id = $row[$lkey]; + +// $ref_schema = App::conf('tables'); +// $ref_schema = $ref_schema[$parent]; + $ref_schema = $fk['']; + + if ($ref_schema['select']) + { + foreach ($ref_schema['select'] as $a => $b) + { + $select .= ", $b AS `{$a}`"; + } + } + + $sql = "SELECT $select FROM `{$parent}` WHERE `{$fkey}` = ?"; + + $stmt = DB::query($sql, array($parent_id)); + $this->data[$i][$parent] = $stmt->fetchAll(PDO::FETCH_ASSOC); + + } + + } + + private function find_parents() + { + + } + + /** + * Insert this thing in the DB and return inserted + * Thing + */ + public function insert($data) + { + if (empty($data)) { + return App::error('Cannot insert emptiness'); + } + + $insert = ''; + $values = array(); + + foreach($data as $k => $v) + { + $insert .= "`{$k}`, "; + $values[":{$k}"] = $v; + } + + $insert = rtrim($insert, ', '); + $val = implode(', ', array_keys($values)); + $sql = "INSERT INTO `{$this->table}` ({$insert}) VALUES ({$val})"; + + return DB::query($sql, $values); + + } + + /** + * Delete This Thing + */ + protected function delete($where, $limit = '') + { + if (empty($where)) { + return App::error('Cannot delete without arguments'); + } + + list($key, $value) = each($where); + + if ($limit) { + $limit = " LIMIT $limit"; + } + + $data = array(":{$key}" => $value); + $sql = "DELETE FROM `{$this->table}` WHERE `{$key}` = :{$key} $limit"; + + return Db::query($sql, $data); + + } + + /** + * Update this Thing + * We keep this in the Controller since it might know + * more about the topmost class + */ + protected function update($data, $where = null) + { + if (!is_array($data)) { + return App::error('Cannot update without parameters'); + } + + if (empty($where)) { + $where = array('id' => 'id'); + } + + $query = ""; $values = array(); + list($col, $val) = each($where); + + if (!isset($data[$col])) { + $data = array_merge($data, $where); + } + + foreach ($data as $k => $v) { + $query .= "`$k` = :$k, "; + $values[":{$k}"] = $v; + } + + $query = rtrim($query, ", "); + $sql = "UPDATE `{$this->table}` SET $query WHERE `$col` = :$col"; + + return Db::query($sql, $values); + + } + + /** + * Render a view + */ + public function render($data = null, $view = null) + { + // Default to the same view as the method + if (!$view) { + $bt = debug_backtrace(); + $view = $bt[1]['function']; + } + + if (!$view) { + $view = $this->defaultAction; + } + + if (!$data) { + $data = $this->view; + } + + $type = App::type(); + // @very temporary hack? + $tpl = (App::url(0) == "admin") ? "admin" : "default"; + $template = "../system/views/{$tpl}.{$type}"; + $file = "../system/views/{$this->table}/{$view}.{$type}"; + + if (!is_file($file)) { + return App::error("{$this->table}_{$view}_{$type}: no such view"); + } + + if ($data) { + foreach ($data as $k => $v) { + $$k = $v; + } + } + + // Capture view + ob_start(); + include $file; + $view_contents = ob_get_contents(); + ob_end_clean(); + + // Capture template + ob_start(); + include $template; + $tpl_contents = ob_get_contents(); + ob_end_clean(); + + $title = ($this->pageTitle) ? $this->pageTitle : App::conf("defaults.title"); + $tpl_contents = preg_replace( + '/.*?<\/title>/', "<title>{$title}", $tpl_contents + ); + + echo str_replace('%%page_content%%', $view_contents, $tpl_contents); + + } + + public function match($cols, $match) + { + foreach ($cols as $col) { + $sql .= "`{$col}`,"; + } + + $sql = rtrim($sql, ","); + $sql = "SELECT * FROM `{$this->table}` WHERE MATCH($sql) AGAINST('{$match}')"; + + return App::db()->query($sql); + + } + + /** + * Insert or update + */ + public function upsert($data, $where = null) + { + if(!$this->get($where)) { + $out = $this->insert($data); + } else { + $out = $this->update($data, $where); + } +// App::log($out); + return $out; + + } + +} + +?> diff --git a/MainDb.php b/MainDb.php new file mode 100644 index 0000000..0922cdf --- /dev/null +++ b/MainDb.php @@ -0,0 +1,116 @@ + +// http://www.php.net/manual/en/language.oop5.patterns.php +class MainDb +{ + private static $instance = NULL; + + private function __construct() + { + + } + + /** + * Open persistent connection to database + */ + public static function getInstance() + { + $c = App::conf(); + + if (!self::$instance) + { + try { + self::$instance = new PDO( + "{$c['db.driver']}:host={$c['db.host']};dbname={$c['db.name']}", + $c['db.username'], $c['db.password'], array(PDO::ATTR_PERSISTENT => true) + ); + + self::$instance->query("SET NAMES utf8"); + + } catch (PDOException $e) { + exit(App::error($e->getMessage())); + } + + } + + return self::$instance; + + } + + /** + * Deny cloning + */ + public function __clone() + { + trigger_error("Cloning not work is", E_USER_ERROR); + } + + /** + * Execute an SQL query + * @return mixed + */ + public static function query($sql, $data = null) + { + if (!$data) { + $data = array(); + } + + // Might be just a string + if (!is_array($data)) { + $data = array($data); + } + + try { + + $pdo = self::getInstance(); + $stmt = $pdo->prepare($sql); + $result = $stmt->execute($data); + + if (!$result) { + list($ec, $dec, $emsg) = $pdo->errorInfo(); + $error = $emsg ."\n" . print_r(debug_backtrace(), true); + return App::error($error); + } + + } catch (PDOException $e) { + $error = $e->getMessage() . $sql; + $error .= "\n" . print_r(debug_backtrace(), true); + return App::error($error); + } + + // Select statements need the query results + if (preg_match('/^SELECT/i', $sql)) { + return $stmt; + } + + if (empty($data['id'])) { + $data['id'] = $pdo->lastInsertId(); + } + + $out = array(); + + // Always strip ":" prefixes from input array keys + foreach ($data as $k => $v) { + $key = ltrim($k, ':'); + $out[$key] = $v; + } + + return $out; + + } + + /** + * + */ + public static function fetch($sql, $data = null) + { + $stmt = self::query($sql, $data) + or exit(App::error("Error executing query $sql")); + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + +} + +?> \ No newline at end of file diff --git a/MainView.php b/MainView.php new file mode 100644 index 0000000..d964b6c --- /dev/null +++ b/MainView.php @@ -0,0 +1,67 @@ + +class MainView +{ + /** + * Create HTML options from array - * @param array array - * @param mixed select option with this value - * @return string - */ - function select($array, $current = null) - { - $out = ''; - - foreach ($array as $k => $v) { - $sel = ($k == $current) ? ' selected="selected" ' : ''; - $out .= "\n\t"; - } - - return $out; - - } - - function tag($name, $args = '', $content = '', $selected = '') - { - $str_args = ''; - $out = '<' . $name; - - // special treatment for certain tags - switch ($name) - { - case 'form': - break; - case 'img': - if (empty ($args['alt'])) $args['alt'] = 'Image'; - break; - } - - if (is_array ($args)) - { - while (list ($k, $v) = each ($args)) { - if (!empty ($k)) $str_args .= ' ' . $k . '="' . $v . '"'; - } - } - - if (is_array ($content)) - { - foreach ($content as $k => $v) - { - // - } - } else { - // - } - - if (empty ($content)) return $out . $str_args . ' />'; - - return "{$out}{$str_args}>{$content}\n"; - - } - -} - -?> \ No newline at end of file -- cgit v1.2.3