diff --git a/vendor/notorm/NotORM.php b/vendor/notorm/NotORM.php new file mode 100644 index 0000000..ab5232b --- /dev/null +++ b/vendor/notorm/NotORM.php @@ -0,0 +1,104 @@ +connection = $connection; + $this->driver = $connection->getAttribute(PDO::ATTR_DRIVER_NAME); + if (!isset($structure)) { + $structure = new NotORM_Structure_Convention; + } + $this->structure = $structure; + $this->cache = $cache; + } + + /** Get table data to use as $db->table[1] + * @param string + * @return NotORM_Result + */ + function __get($table) { + return new NotORM_Result($this->structure->getReferencingTable($table, ''), $this, true); + } + + /** Set write-only properties + * @return null + */ + function __set($name, $value) { + if ($name == "debug" || $name == "debugTimer" || $name == "freeze" || $name == "rowClass" || $name == "jsonAsArray") { + $this->$name = $value; + } + if ($name == "transaction") { + switch (strtoupper($value)) { + case "BEGIN": return $this->connection->beginTransaction(); + case "COMMIT": return $this->connection->commit(); + case "ROLLBACK": return $this->connection->rollback(); + } + } + } + + /** Get table data + * @param string + * @param array (["condition"[, array("value")]]) passed to NotORM_Result::where() + * @return NotORM_Result + */ + function __call($table, array $where) { + $return = new NotORM_Result($this->structure->getReferencingTable($table, ''), $this); + if ($where) { + call_user_func_array(array($return, 'where'), $where); + } + return $return; + } + +} diff --git a/vendor/notorm/NotORM/Cache.php b/vendor/notorm/NotORM/Cache.php new file mode 100644 index 0000000..e904209 --- /dev/null +++ b/vendor/notorm/NotORM/Cache.php @@ -0,0 +1,187 @@ +filename = $filename; + $this->data = unserialize(@file_get_contents($filename)); // @ - file may not exist + } + + function load($key) { + if (!isset($this->data[$key])) { + return null; + } + return $this->data[$key]; + } + + function save($key, $data) { + if (!isset($this->data[$key]) || $this->data[$key] !== $data) { + $this->data[$key] = $data; + file_put_contents($this->filename, serialize($this->data), LOCK_EX); + } + } + +} + + + +/** Cache using PHP include +*/ +class NotORM_Cache_Include implements NotORM_Cache { + private $filename, $data = array(); + + function __construct($filename) { + $this->filename = $filename; + $this->data = @include realpath($filename); // @ - file may not exist, realpath() to not include from include_path //! silently falls with syntax error and fails with unreadable file + if (!is_array($this->data)) { // empty file returns 1 + $this->data = array(); + } + } + + function load($key) { + if (!isset($this->data[$key])) { + return null; + } + return $this->data[$key]; + } + + function save($key, $data) { + if (!isset($this->data[$key]) || $this->data[$key] !== $data) { + $this->data[$key] = $data; + file_put_contents($this->filename, 'data, true) . ';', LOCK_EX); + } + } + +} + + + +/** Cache storing data to the "notorm" table in database +*/ +class NotORM_Cache_Database implements NotORM_Cache { + private $connection; + + function __construct(PDO $connection) { + $this->connection = $connection; + } + + function load($key) { + $result = $this->connection->prepare("SELECT data FROM notorm WHERE id = ?"); + $result->execute(array($key)); + $return = $result->fetchColumn(); + if (!$return) { + return null; + } + return unserialize($return); + } + + function save($key, $data) { + // REPLACE is not supported by PostgreSQL and MS SQL + $parameters = array(serialize($data), $key); + $result = $this->connection->prepare("UPDATE notorm SET data = ? WHERE id = ?"); + $result->execute($parameters); + if (!$result->rowCount()) { + $result = $this->connection->prepare("INSERT INTO notorm (data, id) VALUES (?, ?)"); + try { + @$result->execute($parameters); // @ - ignore duplicate key error + } catch (PDOException $e) { + if ($e->getCode() != "23000") { // "23000" - duplicate key + throw $e; + } + } + } + } + +} + + + +// eAccelerator - user cache is obsoleted + + + +/** Cache using "NotORM." prefix in Memcache +*/ +class NotORM_Cache_Memcache implements NotORM_Cache { + private $memcache; + + function __construct(Memcache $memcache) { + $this->memcache = $memcache; + } + + function load($key) { + $return = $this->memcache->get("NotORM.$key"); + if ($return === false) { + return null; + } + return $return; + } + + function save($key, $data) { + $this->memcache->set("NotORM.$key", $data); + } + +} + + + +/** Cache using "NotORM." prefix in APC +*/ +class NotORM_Cache_APC implements NotORM_Cache { + + function load($key) { + $return = apc_fetch("NotORM.$key", $success); + if (!$success) { + return null; + } + return $return; + } + + function save($key, $data) { + apc_store("NotORM.$key", $data); + } + +} diff --git a/vendor/notorm/NotORM/Literal.php b/vendor/notorm/NotORM/Literal.php new file mode 100644 index 0000000..d00872d --- /dev/null +++ b/vendor/notorm/NotORM/Literal.php @@ -0,0 +1,29 @@ +value = $value; + $this->parameters = func_get_args(); + array_shift($this->parameters); + } + + /** Get literal value + * @return string + */ + function __toString() { + return $this->value; + } + +} diff --git a/vendor/notorm/NotORM/MultiResult.php b/vendor/notorm/NotORM/MultiResult.php new file mode 100644 index 0000000..2450235 --- /dev/null +++ b/vendor/notorm/NotORM/MultiResult.php @@ -0,0 +1,143 @@ +notORM); + $this->result = $result; + $this->column = $column; + $this->active = $active; + } + + /** Specify referencing column + * @param string + * @return NotORM_MultiResult fluent interface + */ + function via($column) { + $this->column = $column; + $this->conditions[0] = "$this->table.$column AND"; + $this->where[0] = "(" . $this->whereIn("$this->table.$column", array_keys((array) $this->result->rows)) . ")"; + return $this; + } + + function insert_multi(array $rows) { + $args = array(); + foreach ($rows as $data) { + if ($data instanceof Traversable && !$data instanceof NotORM_Result) { + $data = iterator_to_array($data); + } + if (is_array($data)) { + $data[$this->column] = $this->active; + } + $args[] = $data; + } + return parent::insert_multi($args); + } + + function insert_update(array $unique, array $insert, array $update = array()) { + $unique[$this->column] = $this->active; + return parent::insert_update($unique, $insert, $update); + } + + protected function single() { + $this->where[0] = "($this->column = " . $this->quote($this->active) . ")"; + } + + function update(array $data) { + $where = $this->where; + $this->single(); + $return = parent::update($data); + $this->where = $where; + return $return; + } + + function delete() { + $where = $this->where; + $this->single(); + $return = parent::delete(); + $this->where = $where; + return $return; + } + + function select($columns) { + $args = func_get_args(); + if (!$this->select) { + array_unshift($args, "$this->table.$this->column"); + } + return call_user_func_array(array($this, 'parent::select'), $args); + } + + function order($columns) { + if (!$this->order) { // improve index utilization + $this->order[] = "$this->table.$this->column" . (preg_match('~\\bDESC$~i', $columns) ? " DESC" : ""); + } + $args = func_get_args(); + return call_user_func_array(array($this, 'parent::order'), $args); + } + + function aggregation($function) { + $join = $this->createJoins(implode(",", $this->conditions) . ",$function"); + $column = ($join ? "$this->table." : "") . $this->column; + $query = "SELECT $function, $column FROM $this->table" . implode($join); + if ($this->where) { + $query .= " WHERE " . implode($this->where); + } + $query .= " GROUP BY $column"; + $aggregation = &$this->result->aggregation[$query]; + if (!isset($aggregation)) { + $aggregation = array(); + foreach ($this->query($query, $this->parameters) as $row) { + $aggregation[$row[$this->column]] = $row; + } + } + if (isset($aggregation[$this->active])) { + foreach ($aggregation[$this->active] as $return) { + return $return; + } + } + } + + function count($column = "") { + $return = parent::count($column); + return (isset($return) ? $return : 0); + } + + protected function execute() { + if (!isset($this->rows)) { + $referencing = &$this->result->referencing[$this->__toString()]; + if (!isset($referencing)) { + if (!$this->limit || count($this->result->rows) <= 1 || $this->union) { + parent::execute(); + } else { //! doesn't work with union + $result = clone $this; + $first = true; + foreach ((array) $this->result->rows as $val) { + if ($first) { + $result->where[0] = "$this->column = " . $this->quote($val); + $first = false; + } else { + $clone = clone $this; + $clone->where[0] = "$this->column = " . $this->quote($val); + $result->union($clone); + } + } + $result->execute(); + $this->rows = $result->rows; + } + $referencing = array(); + foreach ($this->rows as $key => $row) { + $referencing[$row[$this->column]][$key] = $row; + } + } + $this->data = &$referencing[$this->active]; + if (!isset($this->data)) { + $this->data = array(); + } + } + } + +} diff --git a/vendor/notorm/NotORM/Result.php b/vendor/notorm/NotORM/Result.php new file mode 100644 index 0000000..2e219f5 --- /dev/null +++ b/vendor/notorm/NotORM/Result.php @@ -0,0 +1,830 @@ +table = $table; + $this->notORM = $notORM; + $this->single = $single; + $this->primary = $notORM->structure->getPrimary($table); + } + + /** Save data to cache and empty result + */ + function __destruct() { + if ($this->notORM->cache && !$this->select && isset($this->rows)) { + $access = $this->access; + if (is_array($access)) { + $access = array_filter($access); + } + $this->notORM->cache->save("$this->table;" . implode(",", $this->conditions), $access); + } + $this->rows = null; + unset($this->data); + } + + protected function limitString($limit, $offset = null) { + $return = ""; + if (isset($limit) && $this->notORM->driver != "oci" && $this->notORM->driver != "dblib" && $this->notORM->driver != "mssql" && $this->notORM->driver != "sqlsrv") { + $return .= " LIMIT $limit"; + if ($offset) { + $return .= " OFFSET $offset"; + } + } + return $return; + } + + protected function removeExtraDots($expression) { + return preg_replace('~(?:\\b[a-z_][a-z0-9_.:]*[.:])?([a-z_][a-z0-9_]*)[.:]([a-z_*])~i', '\\1.\\2', $expression); // rewrite tab1.tab2.col + } + + protected function whereString() { + $return = ""; + if ($this->group) { + $return .= " GROUP BY $this->group"; + } + if ($this->having) { + $return .= " HAVING $this->having"; + } + if ($this->order) { + $return .= " ORDER BY " . implode(", ", $this->order); + } + $return = $this->removeExtraDots($return); + + $where = $this->where; + if (isset($this->limit) && $this->notORM->driver == "oci") { + $where[] = ($where ? " AND " : "") . "(" . ($this->offset ? "rownum > $this->offset AND " : "") . "rownum <= " . ($this->limit + $this->offset) . ")"; //! rownum > doesn't work - requires subselect (see adminer/drivers/oracle.inc.php) + } + if ($where) { + $return = " WHERE " . implode($where) . $return; + } + + $return .= $this->limitString($this->limit, $this->offset); + if (isset($this->lock)) { + $return .= ($this->lock ? " FOR UPDATE" : " LOCK IN SHARE MODE"); + } + return $return; + } + + protected function topString($limit, $offset = null) { + if (isset($limit) && ($this->notORM->driver == "dblib" || $this->notORM->driver == "mssql" || $this->notORM->driver == "sqlsrv")) { + return " TOP ($this->limit)"; //! offset is not supported + } + return ""; + } + + protected function createJoins($val) { + $return = array(); + preg_match_all('~\\b([a-z_][a-z0-9_.:]*[.:])[a-z_*]~i', $val, $matches); + foreach ($matches[1] as $names) { + $parent = $this->table; + if ($names != "$parent.") { // case-sensitive + preg_match_all('~\\b([a-z_][a-z0-9_]*)([.:])~i', $names, $matches, PREG_SET_ORDER); + foreach ($matches as $match) { + list(, $name, $delimiter) = $match; + $table = $this->notORM->structure->getReferencedTable($name, $parent); + $column = ($delimiter == ':' ? $this->notORM->structure->getPrimary($parent) : $this->notORM->structure->getReferencedColumn($name, $parent)); + $primary = ($delimiter == ':' ? $this->notORM->structure->getReferencedColumn($parent, $table) : $this->notORM->structure->getPrimary($table)); + $return[$name] = " LEFT JOIN $table" . ($table != $name ? " AS $name" : "") . " ON $parent.$column = $name.$primary"; // should use alias if the table is used on more places + $parent = $name; + } + } + } + return $return; + } + + /** Get SQL query + * @return string + */ + function __toString() { + $return = "SELECT" . $this->topString($this->limit, $this->offset) . " "; + $join = $this->createJoins(implode(",", $this->conditions) . "," . implode(",", $this->select) . ",$this->group,$this->having," . implode(",", $this->order)); + if (!isset($this->rows) && $this->notORM->cache && !is_string($this->accessed)) { + $this->accessed = $this->notORM->cache->load("$this->table;" . implode(",", $this->conditions)); + $this->access = $this->accessed; + } + if ($this->select) { + $return .= $this->removeExtraDots(implode(", ", $this->select)); + } elseif ($this->accessed) { + $return .= ($join ? "$this->table." : "") . implode(", " . ($join ? "$this->table." : ""), array_keys($this->accessed)); + } else { + $return .= ($join ? "$this->table." : "") . "*"; + } + $return .= " FROM $this->table" . implode($join) . $this->whereString(); + if ($this->union) { + $return = ($this->notORM->driver == "sqlite" || $this->notORM->driver == "oci" ? $return : "($return)") . implode($this->union); + if ($this->unionOrder) { + $return .= " ORDER BY " . implode(", ", $this->unionOrder); + } + $return .= $this->limitString($this->unionLimit, $this->unionOffset); + $top = $this->topString($this->unionLimit, $this->unionOffset); + if ($top) { + $return = "SELECT$top * FROM ($return) t"; + } + } + return $return; + } + + protected function query($query, $parameters) { + if ($this->notORM->debug) { + if (!is_callable($this->notORM->debug)) { + $debug = "$query;"; + if ($parameters) { + $debug .= " -- " . implode(", ", array_map(array($this, 'quote'), $parameters)); + } + $pattern = '(^' . preg_quote(dirname(__FILE__)) . '(\\.php$|[/\\\\]))'; // can be static + foreach (debug_backtrace() as $backtrace) { + if (isset($backtrace["file"]) && !preg_match($pattern, $backtrace["file"])) { // stop on first file outside NotORM source codes + break; + } + } + error_log("$backtrace[file]:$backtrace[line]:$debug\n", 0); + } elseif (call_user_func($this->notORM->debug, $query, $parameters) === false) { + return false; + } + } + $return = $this->notORM->connection->prepare($query); + if (!$return || !$return->execute(array_map(array($this, 'formatValue'), $parameters))) { + $return = false; + } + if ($this->notORM->debugTimer) { + call_user_func($this->notORM->debugTimer); + } + return $return; + } + + protected function formatValue($val) { + if ($val instanceof DateTime) { + return $val->format("Y-m-d H:i:s"); //! may be driver specific + } + return $val; + } + + protected function quote($val) { + if (!isset($val)) { + return "NULL"; + } + if (is_array($val)) { // (a, b) IN ((1, 2), (3, 4)) + return "(" . implode(", ", array_map(array($this, 'quote'), $val)) . ")"; + } + $val = $this->formatValue($val); + if (is_float($val)) { + return sprintf("%F", $val); // otherwise depends on setlocale() + } + if ($val === false) { + return "0"; + } + if (is_int($val) || $val instanceof NotORM_Literal) { // number or SQL code - for example "NOW()" + return (string) $val; + } + return $this->notORM->connection->quote($val); + } + + /** Shortcut for call_user_func_array(array($this, 'insert'), $rows) + * @param array + * @return int number of affected rows or false in case of an error + */ + function insert_multi(array $rows) { + if ($this->notORM->freeze) { + return false; + } + if (!$rows) { + return 0; + } + $data = reset($rows); + $parameters = array(); + if ($data instanceof NotORM_Result) { + $parameters = $data->parameters; //! other parameters + $data = (string) $data; + } elseif ($data instanceof Traversable) { + $data = iterator_to_array($data); + } + $insert = $data; + if (is_array($data)) { + $values = array(); + foreach ($rows as $value) { + if ($value instanceof Traversable) { + $value = iterator_to_array($value); + } + $values[] = $this->quote($value); + foreach ($value as $val) { + if ($val instanceof NotORM_Literal && $val->parameters) { + $parameters = array_merge($parameters, $val->parameters); + } + } + } + //! driver specific extended insert + $insert = ($data || $this->notORM->driver == "mysql" + ? "(" . implode(", ", array_keys($data)) . ") VALUES " . implode(", ", $values) + : "DEFAULT VALUES" + ); + } + // requires empty $this->parameters + $return = $this->query("INSERT INTO $this->table $insert", $parameters); + if (!$return) { + return false; + } + $this->rows = null; + return $return->rowCount(); + } + + /** Insert row in a table + * @param mixed array($column => $value)|Traversable for single row insert or NotORM_Result|string for INSERT ... SELECT + * @param ... used for extended insert + * @return mixed inserted NotORM_Row or false in case of an error or number of affected rows for INSERT ... SELECT + */ + function insert($data) { + $rows = func_get_args(); + $return = $this->insert_multi($rows); + if (!$return) { + return false; + } + if (!is_array($data)) { + return $return; + } + if (!isset($data[$this->primary]) && ($id = $this->notORM->connection->lastInsertId($this->notORM->structure->getSequence($this->table)))) { + $data[$this->primary] = $id; + } + return new $this->notORM->rowClass($data, $this); + } + + /** Update all rows in result set + * @param array ($column => $value) + * @return int number of affected rows or false in case of an error + */ + function update(array $data) { + if ($this->notORM->freeze) { + return false; + } + if (!$data) { + return 0; + } + $values = array(); + $parameters = array(); + foreach ($data as $key => $val) { + // doesn't use binding because $this->parameters can be filled by ? or :name + $values[] = "$key = " . $this->quote($val); + if ($val instanceof NotORM_Literal && $val->parameters) { + $parameters = array_merge($parameters, $val->parameters); + } + } + if ($this->parameters) { + $parameters = array_merge($parameters, $this->parameters); + } + // joins in UPDATE are supported only in MySQL + $return = $this->query("UPDATE" . $this->topString($this->limit, $this->offset) . " $this->table SET " . implode(", ", $values) . $this->whereString(), $parameters); + if (!$return) { + return false; + } + return $return->rowCount(); + } + + /** Insert row or update if it already exists + * @param array ($column => $value) + * @param array ($column => $value) + * @param array ($column => $value), empty array means use $insert + * @return int number of affected rows or false in case of an error + */ + function insert_update(array $unique, array $insert, array $update = array()) { + if (!$update) { + $update = $insert; + } + $insert = $unique + $insert; + $values = "(" . implode(", ", array_keys($insert)) . ") VALUES " . $this->quote($insert); + //! parameters + if ($this->notORM->driver == "mysql") { + $set = array(); + if (!$update) { + $update = $unique; + } + foreach ($update as $key => $val) { + $set[] = "$key = " . $this->quote($val); + //! parameters + } + return $this->insert("$values ON DUPLICATE KEY UPDATE " . implode(", ", $set)); + } else { + $connection = $this->notORM->connection; + $errorMode = $connection->getAttribute(PDO::ATTR_ERRMODE); + $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + try { + $return = $this->insert($values); + $connection->setAttribute(PDO::ATTR_ERRMODE, $errorMode); + return $return; + } catch (PDOException $e) { + $connection->setAttribute(PDO::ATTR_ERRMODE, $errorMode); + if ($e->getCode() == "23000" || $e->getCode() == "23505") { // "23000" - duplicate key, "23505" unique constraint pgsql + if (!$update) { + return 0; + } + $clone = clone $this; + $return = $clone->where($unique)->update($update); + return ($return ? $return + 1 : $return); + } + if ($errorMode == PDO::ERRMODE_EXCEPTION) { + throw $e; + } elseif ($errorMode == PDO::ERRMODE_WARNING) { + trigger_error("PDOStatement::execute(): " . $e->getMessage(), E_USER_WARNING); // E_WARNING is unusable + } + } + } + } + + /** Get last insert ID + * @return string number + */ + function insert_id() { + return $this->notORM->connection->lastInsertId(); + } + + /** Delete all rows in result set + * @return int number of affected rows or false in case of an error + */ + function delete() { + if ($this->notORM->freeze) { + return false; + } + $return = $this->query("DELETE" . $this->topString($this->limit, $this->offset) . " FROM $this->table" . $this->whereString(), $this->parameters); + if (!$return) { + return false; + } + return $return->rowCount(); + } + + /** Add select clause, more calls appends to the end + * @param string for example "column, MD5(column) AS column_md5", empty string to reset previously set columns + * @param string ... + * @return NotORM_Result fluent interface + */ + function select($columns) { + $this->__destruct(); + if ($columns != "") { + foreach (func_get_args() as $columns) { + $this->select[] = $columns; + } + } else { + $this->select = array(); + } + return $this; + } + + /** Add where condition, more calls appends with AND + * @param mixed string possibly containing ? or :name; or array($condition => $parameters, ...) + * @param mixed array accepted by PDOStatement::execute or a scalar value + * @param mixed ... + * @return NotORM_Result fluent interface + */ + function where($condition, $parameters = array()) { + $args = func_get_args(); + return $this->whereOperator("AND", $args); + } + + protected function whereOperator($operator, array $args) { + $condition = $args[0]; + $parameters = (count($args) > 1 ? $args[1] : array()); + if (is_array($condition)) { // where(array("column1" => 1, "column2 > ?" => 2)) + foreach ($condition as $key => $val) { + $this->where($key, $val); + } + return $this; + } + $this->__destruct(); + $this->conditions[] = "$operator $condition"; + $condition = $this->removeExtraDots($condition); + if (count($args) != 2 || strpbrk($condition, "?:")) { // where("column < ? OR column > ?", array(1, 2)) + if (count($args) != 2 || !is_array($parameters)) { // where("column < ? OR column > ?", 1, 2) + $parameters = array_slice($args, 1); + } + $this->parameters = array_merge($this->parameters, $parameters); + } elseif ($parameters === null) { // where("column", null) + $condition .= " IS NULL"; + } elseif ($parameters instanceof NotORM_Result) { // where("column", $db->$table()) + $clone = clone $parameters; + if (!$clone->select) { + $clone->select($this->notORM->structure->getPrimary($clone->table)); + } + if ($this->notORM->driver != "mysql") { + if ($clone instanceof NotORM_MultiResult) { + array_shift($clone->select); + $clone->single(); + } + $condition .= " IN ($clone)"; + $this->parameters = array_merge($this->parameters, $clone->parameters); + } else { + $in = array(); + foreach ($clone as $row) { + $row = array_values(iterator_to_array($row)); + if ($clone instanceof NotORM_MultiResult && count($row) > 1) { + array_shift($row); + } + if (count($row) == 1) { + $in[] = $this->quote($row[0]); + } else { + $in[] = $this->quote($row); + } + } + if ($in) { + $condition .= " IN (" . implode(", ", $in) . ")"; + } else { + $condition = "($condition) IS NOT NULL AND $condition IS NULL"; // $condition = "NOT id" + } + } + } elseif (!is_array($parameters)) { // where("column", "x") + $condition .= " = " . $this->quote($parameters); + } else { // where("column", array(1, 2)) + $condition = $this->whereIn($condition, $parameters); + } + $this->where[] = (preg_match('~^\)+$~', $condition) + ? $condition + : ($this->where ? " $operator " : "") . "($condition)" + ); + return $this; + } + + protected function whereIn($condition, $parameters) { + if (!$parameters) { + $condition = "($condition) IS NOT NULL AND $condition IS NULL"; + } elseif ($this->notORM->driver != "oci") { + $column = $condition; + $condition .= " IN " . $this->quote($parameters); + $nulls = array_filter($parameters, 'is_null'); + if ($nulls) { + $condition = "$condition OR $column IS NULL"; + } + } else { // http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/expressions014.htm + $or = array(); + for ($i=0; $i < count($parameters); $i += 1000) { + $or[] = "$condition IN " . $this->quote(array_slice($parameters, $i, 1000)); + } + $condition = implode(" OR ", $or); + } + return $condition; + } + + function __call($name, array $args) { + $operator = strtoupper($name); + switch ($operator) { + case "AND": + case "OR": + return $this->whereOperator($operator, $args); + } + trigger_error("Call to undefined method NotORM_Result::$name()", E_USER_ERROR); + } + + /** Shortcut for where() + * @param string + * @param mixed + * @param mixed ... + * @return NotORM_Result fluent interface + */ + function __invoke($where, $parameters = array()) { + $args = func_get_args(); + return $this->whereOperator("AND", $args); + } + + /** Add order clause, more calls appends to the end + * @param mixed "column1, column2 DESC" or array("column1", "column2 DESC"), empty string to reset previous order + * @param string ... + * @return NotORM_Result fluent interface + */ + function order($columns) { + $this->rows = null; + if ($columns != "") { + $columns = (is_array($columns) ? $columns : func_get_args()); + foreach ($columns as $column) { + if ($this->union) { + $this->unionOrder[] = $column; + } else { + $this->order[] = $column; + } + } + } elseif ($this->union) { + $this->unionOrder = array(); + } else { + $this->order = array(); + } + return $this; + } + + /** Set limit clause, more calls rewrite old values + * @param int + * @param int + * @return NotORM_Result fluent interface + */ + function limit($limit, $offset = null) { + $this->rows = null; + if ($this->union) { + $this->unionLimit = +$limit; + $this->unionOffset = +$offset; + } else { + $this->limit = +$limit; + $this->offset = +$offset; + } + return $this; + } + + /** Set group clause, more calls rewrite old values + * @param string + * @param string + * @return NotORM_Result fluent interface + */ + function group($columns, $having = "") { + $this->__destruct(); + $this->group = $columns; + $this->having = $having; + return $this; + } + + /** Set select FOR UPDATE or LOCK IN SHARE MODE + * @param bool + * @return NotORM_Result fluent interface + */ + function lock($exclusive = true) { + $this->lock = $exclusive; + return $this; + } + + /** + * @param NotORM_Result + * @param bool + * @return NotORM_Result fluent interface + */ + function union(NotORM_Result $result, $all = false) { + $this->union[] = " UNION " . ($all ? "ALL " : "") . ($this->notORM->driver == "sqlite" || $this->notORM->driver == "oci" ? $result : "($result)"); + $this->parameters = array_merge($this->parameters, $result->parameters); + return $this; + } + + /** Execute aggregation function + * @param string + * @return string + */ + function aggregation($function) { + $join = $this->createJoins(implode(",", $this->conditions) . ",$function"); + $query = "SELECT $function FROM $this->table" . implode($join); + if ($this->where) { + $query .= " WHERE " . implode($this->where); + } + foreach ($this->query($query, $this->parameters)->fetch() as $return) { + return $return; + } + } + + /** Count number of rows + * @param string + * @return int + */ + function count($column = "") { + if (!$column) { + $this->execute(); + return count($this->data); + } + return $this->aggregation("COUNT($column)"); + } + + /** Return minimum value from a column + * @param string + * @return int + */ + function min($column) { + return $this->aggregation("MIN($column)"); + } + + /** Return maximum value from a column + * @param string + * @return int + */ + function max($column) { + return $this->aggregation("MAX($column)"); + } + + /** Return sum of values in a column + * @param string + * @return int + */ + function sum($column) { + return $this->aggregation("SUM($column)"); + } + + /** Execute the built query + * @return null + */ + protected function execute() { + if (!isset($this->rows)) { + $result = false; + $exception = null; + $parameters = array(); + foreach (array_merge($this->select, array($this, $this->group, $this->having), $this->order, $this->unionOrder) as $val) { + if (($val instanceof NotORM_Literal || $val instanceof self) && $val->parameters) { + $parameters = array_merge($parameters, $val->parameters); + } + } + try { + $result = $this->query($this->__toString(), $parameters); + } catch (PDOException $exception) { + // handled later + } + if (!$result) { + if (!$this->select && $this->accessed) { + $this->accessed = ''; + $this->access = array(); + $result = $this->query($this->__toString(), $parameters); + } elseif ($exception) { + throw $exception; + } + } + $this->rows = array(); + if ($result) { + $result->setFetchMode(PDO::FETCH_ASSOC); + foreach ($result as $key => $row) { + if (isset($row[$this->primary])) { + $key = $row[$this->primary]; + if (!is_string($this->access)) { + $this->access[$this->primary] = true; + } + } + $this->rows[$key] = new $this->notORM->rowClass($row, $this); + } + } + $this->data = $this->rows; + } + } + + /** Fetch next row of result + * @param string column name to return or an empty string for the whole row + * @return mixed string or null with $column, NotORM_Row without $column, false if there is no row + */ + function fetch($column = '') { + // no $this->select($column) because next calls can access different columns + $this->execute(); + $return = current($this->data); + next($this->data); + if ($return && $column != '') { + return $return[$column]; + } + return $return; + } + + /** Fetch all rows as associative array + * @param string + * @param string column name used for an array value or an empty string for the whole row + * @return array + */ + function fetchPairs($key, $value = '') { + $return = array(); + $clone = clone $this; + if ($value != "") { + $clone->select = array(); + $clone->select("$key, $value"); // MultiResult adds its column + } elseif ($clone->select) { + array_unshift($clone->select, $key); + } else { + $clone->select = array("$key, $this->table.*"); + } + foreach ($clone as $row) { + $values = array_values(iterator_to_array($row)); + if ($value != "" && $clone instanceof NotORM_MultiResult) { + array_shift($values); + } + $return[(string) $values[0]] = ($value != "" ? $values[(array_key_exists(1, $values) ? 1 : 0)] : $row); // isset($values[1]) - fetchPairs("id", "id") + } + return $return; + } + + protected function access($key, $delete = false) { + if ($delete) { + if (is_array($this->access)) { + $this->access[$key] = false; + } + return false; + } + if (!isset($key)) { + $this->access = ''; + } elseif (!is_string($this->access)) { + $this->access[$key] = true; + } + if (!$this->select && $this->accessed && (!isset($key) || !isset($this->accessed[$key]))) { + $this->accessed = ''; + $this->rows = null; + return true; + } + return false; + } + + protected function single() { + } + + // Iterator implementation (not IteratorAggregate because $this->data can be changed during iteration) + + function rewind() { + $this->execute(); + $this->keys = array_keys($this->data); + reset($this->keys); + } + + /** @return NotORM_Row */ + function current() { + return $this->data[current($this->keys)]; + } + + /** @return string row ID */ + function key() { + return current($this->keys); + } + + function next() { + next($this->keys); + } + + function valid() { + return current($this->keys) !== false; + } + + // ArrayAccess implementation + + /** Test if row exists + * @param string row ID or array for where conditions + * @return bool + */ + function offsetExists($key) { + $row = $this->offsetGet($key); + return isset($row); + } + + /** Get specified row + * @param string row ID or array for where conditions + * @return NotORM_Row or null if there is no such row + */ + function offsetGet($key) { + if ($this->single && !isset($this->data)) { + $clone = clone $this; + if (is_array($key)) { + $clone->where($key)->limit(1); + } else { + $clone->where($this->primary, $key); + } + $return = $clone->fetch(); + if ($return) { + return $return; + } + } else { + $this->execute(); + if (is_array($key)) { + foreach ($this->data as $row) { + foreach ($key as $k => $v) { + if ((isset($v) && $row[$k] !== null ? $row[$k] != $v : $row[$k] !== $v)) { + continue 2; + } + } + return $row; + } + } elseif (isset($this->data[$key])) { + return $this->data[$key]; + } + } + } + + /** Mimic row + * @param string row ID + * @param NotORM_Row + * @return null + */ + function offsetSet($key, $value) { + $this->execute(); + $this->data[$key] = $value; + } + + /** Remove row from result set + * @param string row ID + * @return null + */ + function offsetUnset($key) { + $this->execute(); + unset($this->data[$key]); + } + + // JsonSerializable implementation + + function jsonSerialize() { + $this->execute(); + if ($this->notORM->jsonAsArray) { + return array_values($this->data); + } else { + return $this->data; + } + } + +} diff --git a/vendor/notorm/NotORM/Row.php b/vendor/notorm/NotORM/Row.php new file mode 100644 index 0000000..051c227 --- /dev/null +++ b/vendor/notorm/NotORM/Row.php @@ -0,0 +1,193 @@ +row = $row; + $this->result = $result; + if (array_key_exists($result->primary, $row)) { + $this->primary = $row[$result->primary]; + } + } + + /** Get primary key value + * @return string + */ + function __toString() { + return (string) $this[$this->result->primary]; // (string) - PostgreSQL returns int + } + + /** Get referenced row + * @param string + * @return NotORM_Row or null if the row does not exist + */ + function __get($name) { + $column = $this->result->notORM->structure->getReferencedColumn($name, $this->result->table); + $referenced = &$this->result->referenced[$name]; + if (!isset($referenced)) { + $keys = array(); + foreach ($this->result->rows as $row) { + if ($row[$column] !== null) { + $keys[$row[$column]] = null; + } + } + if ($keys) { + $table = $this->result->notORM->structure->getReferencedTable($name, $this->result->table); + $referenced = new NotORM_Result($table, $this->result->notORM); + $referenced->where("$table." . $this->result->notORM->structure->getPrimary($table), array_keys($keys)); + } else { + $referenced = array(); + } + } + if (!isset($referenced[$this[$column]])) { // referenced row may not exist + return null; + } + return $referenced[$this[$column]]; + } + + /** Test if referenced row exists + * @param string + * @return bool + */ + function __isset($name) { + return ($this->__get($name) !== null); + } + + /** Store referenced value + * @param string + * @param NotORM_Row or null + * @return null + */ + function __set($name, NotORM_Row $value = null) { + $column = $this->result->notORM->structure->getReferencedColumn($name, $this->result->table); + $this[$column] = $value; + } + + /** Remove referenced column from data + * @param string + * @return null + */ + function __unset($name) { + $column = $this->result->notORM->structure->getReferencedColumn($name, $this->result->table); + unset($this[$column]); + } + + /** Get referencing rows + * @param string table name + * @param array (["condition"[, array("value")]]) + * @return NotORM_MultiResult + */ + function __call($name, array $args) { + $table = $this->result->notORM->structure->getReferencingTable($name, $this->result->table); + $column = $this->result->notORM->structure->getReferencingColumn($table, $this->result->table); + $return = new NotORM_MultiResult($table, $this->result, $column, $this[$this->result->primary]); + $return->where("$table.$column", array_keys((array) $this->result->rows)); // (array) - is null after insert + if ($args) { + call_user_func_array(array($return, 'where'), $args); + } + return $return; + } + + /** Update row + * @param array or null for all modified values + * @return int number of affected rows or false in case of an error + */ + function update($data = null) { + // update is an SQL keyword + if (!isset($data)) { + $data = $this->modified; + } + $result = new NotORM_Result($this->result->table, $this->result->notORM); + $return = $result->where($this->result->primary, $this->primary)->update($data); + $this->primary = $this[$this->result->primary]; + return $return; + } + + /** Delete row + * @return int number of affected rows or false in case of an error + */ + function delete() { + // delete is an SQL keyword + $result = new NotORM_Result($this->result->table, $this->result->notORM); + $return = $result->where($this->result->primary, $this->primary)->delete(); + $this->primary = $this[$this->result->primary]; + return $return; + } + + protected function access($key, $delete = false) { + if ($this->result->notORM->cache && !isset($this->modified[$key]) && $this->result->access($key, $delete)) { + $id = (isset($this->primary) ? $this->primary : $this->row); + $this->row = $this->result[$id]->row; + } + } + + // IteratorAggregate implementation + + function getIterator() { + $this->access(null); + return new ArrayIterator($this->row); + } + + // Countable implementation + + function count() { + return count($this->row); + } + + // ArrayAccess implementation + + /** Test if column exists + * @param string column name + * @return bool + */ + function offsetExists($key) { + $this->access($key); + $return = array_key_exists($key, $this->row); + if (!$return) { + $this->access($key, true); + } + return $return; + } + + /** Get value of column + * @param string column name + * @return string + */ + function offsetGet($key) { + $this->access($key); + if (!array_key_exists($key, $this->row)) { + $this->access($key, true); + } + return $this->row[$key]; + } + + /** Store value in column + * @param string column name + * @return null + */ + function offsetSet($key, $value) { + $this->row[$key] = $value; + $this->modified[$key] = $value; + } + + /** Remove column from data + * @param string column name + * @return null + */ + function offsetUnset($key) { + unset($this->row[$key]); + unset($this->modified[$key]); + } + + // JsonSerializable implementation + + function jsonSerialize() { + return $this->row; + } + +} diff --git a/vendor/notorm/NotORM/Structure.php b/vendor/notorm/NotORM/Structure.php new file mode 100644 index 0000000..7394768 --- /dev/null +++ b/vendor/notorm/NotORM/Structure.php @@ -0,0 +1,196 @@ +$table() + * @param string + * @return string + */ + function getPrimary($table); + + /** Get column holding foreign key in $table[$id]->$name() + * @param string + * @param string + * @return string + */ + function getReferencingColumn($name, $table); + + /** Get target table in $table[$id]->$name() + * @param string + * @param string + * @return string + */ + function getReferencingTable($name, $table); + + /** Get column holding foreign key in $table[$id]->$name + * @param string + * @param string + * @return string + */ + function getReferencedColumn($name, $table); + + /** Get table holding foreign key in $table[$id]->$name + * @param string + * @param string + * @return string + */ + function getReferencedTable($name, $table); + + /** Get sequence name, used by insert + * @param string + * @return string + */ + function getSequence($table); + +} + + + +/** Structure described by some rules +*/ +class NotORM_Structure_Convention implements NotORM_Structure { + protected $primary, $foreign, $table, $prefix; + + /** Create conventional structure + * @param string %s stands for table name + * @param string %1$s stands for key used after ->, %2$s for table name + * @param string %1$s stands for key used after ->, %2$s for table name + * @param string prefix for all tables + */ + function __construct($primary = 'id', $foreign = '%s_id', $table = '%s', $prefix = '') { + $this->primary = $primary; + $this->foreign = $foreign; + $this->table = $table; + $this->prefix = $prefix; + } + + function getPrimary($table) { + return sprintf($this->primary, $this->getColumnFromTable($table)); + } + + function getReferencingColumn($name, $table) { + return $this->getReferencedColumn(substr($table, strlen($this->prefix)), $this->prefix . $name); + } + + function getReferencingTable($name, $table) { + return $this->prefix . $name; + } + + function getReferencedColumn($name, $table) { + return sprintf($this->foreign, $this->getColumnFromTable($name), substr($table, strlen($this->prefix))); + } + + function getReferencedTable($name, $table) { + return $this->prefix . sprintf($this->table, $name, $table); + } + + function getSequence($table) { + return null; + } + + protected function getColumnFromTable($name) { + if ($this->table != '%s' && preg_match('(^' . str_replace('%s', '(.*)', preg_quote($this->table)) . '$)', $name, $match)) { + return $match[1]; + } + return $name; + } + +} + + + +/** Structure reading meta-informations from the database +*/ +class NotORM_Structure_Discovery implements NotORM_Structure { + protected $connection, $cache, $structure = array(); + protected $foreign; + + /** Create autodisovery structure + * @param PDO + * @param NotORM_Cache + * @param string use "%s_id" to access $name . "_id" column in $row->$name + */ + function __construct(PDO $connection, NotORM_Cache $cache = null, $foreign = '%s') { + $this->connection = $connection; + $this->cache = $cache; + $this->foreign = $foreign; + if ($cache) { + $this->structure = $cache->load("structure"); + } + } + + /** Save data to cache + */ + function __destruct() { + if ($this->cache) { + $this->cache->save("structure", $this->structure); + } + } + + function getPrimary($table) { + $return = &$this->structure["primary"][$table]; + if (!isset($return)) { + $return = ""; + foreach ($this->connection->query("EXPLAIN $table") as $column) { + if ($column[3] == "PRI") { // 3 - "Key" is not compatible with PDO::CASE_LOWER + if ($return != "") { + $return = ""; // multi-column primary key is not supported + break; + } + $return = $column[0]; + } + } + } + return $return; + } + + function getReferencingColumn($name, $table) { + $name = strtolower($name); + $return = &$this->structure["referencing"][$table]; + if (!isset($return[$name])) { + foreach ($this->connection->query(" + SELECT TABLE_NAME, COLUMN_NAME + FROM information_schema.KEY_COLUMN_USAGE + WHERE TABLE_SCHEMA = DATABASE() + AND REFERENCED_TABLE_SCHEMA = DATABASE() + AND REFERENCED_TABLE_NAME = " . $this->connection->quote($table) . " + AND REFERENCED_COLUMN_NAME = " . $this->connection->quote($this->getPrimary($table)) //! may not reference primary key + ) as $row) { + $return[strtolower($row[0])] = $row[1]; + } + } + return $return[$name]; + } + + function getReferencingTable($name, $table) { + return $name; + } + + function getReferencedColumn($name, $table) { + return sprintf($this->foreign, $name); + } + + function getReferencedTable($name, $table) { + $column = strtolower($this->getReferencedColumn($name, $table)); + $return = &$this->structure["referenced"][$table]; + if (!isset($return[$column])) { + foreach ($this->connection->query(" + SELECT COLUMN_NAME, REFERENCED_TABLE_NAME + FROM information_schema.KEY_COLUMN_USAGE + WHERE TABLE_SCHEMA = DATABASE() + AND REFERENCED_TABLE_SCHEMA = DATABASE() + AND TABLE_NAME = " . $this->connection->quote($table) . " + ") as $row) { + $return[strtolower($row[0])] = $row[1]; + } + } + return $return[$column]; + } + + function getSequence($table) { + return null; + } + +} diff --git a/vendor/notorm/composer.json b/vendor/notorm/composer.json new file mode 100644 index 0000000..2b5cccf --- /dev/null +++ b/vendor/notorm/composer.json @@ -0,0 +1,16 @@ +{ + "name": "vrana/notorm", + "description": "NotORM is a PHP library for simple working with data in the database.", + "keywords": ["database", "dbal"], + "homepage": "http://www.notorm.com/", + "license": ["Apache-2.0", "GPL-2.0+"], + "authors": [ + { + "name": "Jakub Vrána", + "homepage": "http://www.vrana.cz/" + } + ], + "autoload": { + "files": ["NotORM.php"] + } +} diff --git a/vendor/notorm/readme.txt b/vendor/notorm/readme.txt new file mode 100644 index 0000000..52a82fc --- /dev/null +++ b/vendor/notorm/readme.txt @@ -0,0 +1,22 @@ +NotORM - http://www.notorm.com/ + +NotORM is a PHP library for simple working with data in the database. The most interesting feature is a very easy work with table relationships. The overall performance is also very important and NotORM can actually run faster than a native driver. + +Requirements: +PHP 5.1+ +any database supported by PDO (tested with MySQL, SQLite, PostgreSQL, MS SQL, Oracle) + +Usage: +application()->order("title") as $application) { // get all applications ordered by title + echo "$application[title]\n"; // print application title + echo $application->author["name"] . "\n"; // print name of the application author + foreach ($application->application_tag() as $application_tag) { // get all tags of $application + echo $application_tag->tag["name"] . "\n"; // print the tag name + } +} +?> diff --git a/vendor/notorm/tests/1-basic.phpt b/vendor/notorm/tests/1-basic.phpt new file mode 100644 index 0000000..2a4c8ef --- /dev/null +++ b/vendor/notorm/tests/1-basic.phpt @@ -0,0 +1,24 @@ +--TEST-- +Basic operations +--FILE-- +application() as $application) { + echo "$application[title] (" . $application->author["name"] . ")\n"; + foreach ($application->application_tag() as $application_tag) { + echo "\t" . $application_tag->tag["name"] . "\n"; + } +} +?> +--EXPECTF-- +Adminer (Jakub Vrana) + PHP + MySQL +JUSH (Jakub Vrana) + JavaScript +Nette (David Grudl) + PHP +Dibi (David Grudl) + PHP + MySQL diff --git a/vendor/notorm/tests/10-update.phpt b/vendor/notorm/tests/10-update.phpt new file mode 100644 index 0000000..3979af6 --- /dev/null +++ b/vendor/notorm/tests/10-update.phpt @@ -0,0 +1,34 @@ +--TEST-- +Insert, update, delete +--FILE-- +application()->insert(array( + "id" => $id, + "author_id" => $software->author[12], + "title" => new NotORM_Literal("'Texy'"), + "web" => "", + "slogan" => "The best humane Web text generator", +)); +$application_tag = $application->application_tag()->insert(array("tag_id" => 21)); + +// retrieve the really stored value +$application = $software->application[$id]; +echo $application["title"] . "\n"; + +$application["web"] = "http://texy.info/"; +echo $application->update() . " row updated.\n"; +echo $software->application[$id]["web"] . "\n"; + +$software->application_tag("application_id", 5)->delete(); // foreign keys may be disabled +echo $application->delete() . " row deleted.\n"; +echo count($software->application("id", $id)) . " rows found.\n"; +?> +--EXPECTF-- +Texy +1 row updated. +http://texy.info/ +1 row deleted. +0 rows found. diff --git a/vendor/notorm/tests/11-pairs.phpt b/vendor/notorm/tests/11-pairs.phpt new file mode 100644 index 0000000..654bfda --- /dev/null +++ b/vendor/notorm/tests/11-pairs.phpt @@ -0,0 +1,24 @@ +--TEST-- +fetchPairs() +--FILE-- +application()->order("title")->fetchPairs("id", "title")); +print_r($software->application()->order("id")->fetchPairs("id", "id")); +?> +--EXPECTF-- +Array +( + [1] => Adminer + [4] => Dibi + [2] => JUSH + [3] => Nette +) +Array +( + [1] => 1 + [2] => 2 + [3] => 3 + [4] => 4 +) diff --git a/vendor/notorm/tests/12-via.phpt b/vendor/notorm/tests/12-via.phpt new file mode 100644 index 0000000..ff45e7c --- /dev/null +++ b/vendor/notorm/tests/12-via.phpt @@ -0,0 +1,19 @@ +--TEST-- +via() +--FILE-- +author() as $author) { + $applications = $author->application()->via("maintainer_id"); + foreach ($applications as $application) { + echo "$author[name]: $application[title]\n"; + } +} +echo "$applications\n"; +?> +--EXPECTF-- +Jakub Vrana: Adminer +David Grudl: Nette +David Grudl: Dibi +SELECT * FROM application WHERE (application.maintainer_id IN (11, 12)) diff --git a/vendor/notorm/tests/13-join.phpt b/vendor/notorm/tests/13-join.phpt new file mode 100644 index 0000000..e20f8b4 --- /dev/null +++ b/vendor/notorm/tests/13-join.phpt @@ -0,0 +1,24 @@ +--TEST-- +ORDER from other table +--FILE-- +application()->order("author.name, title") as $application) { + echo $application->author["name"] . ": $application[title]\n"; +} +echo "\n"; + +foreach ($software->application_tag("application.author.name", "Jakub Vrana")->group("application_tag.tag_id") as $application_tag) { + echo $application_tag->tag["name"] . "\n"; +} +?> +--EXPECTF-- +David Grudl: Dibi +David Grudl: Nette +Jakub Vrana: Adminer +Jakub Vrana: JUSH + +PHP +MySQL +JavaScript diff --git a/vendor/notorm/tests/14-where.phpt b/vendor/notorm/tests/14-where.phpt new file mode 100644 index 0000000..a656934 --- /dev/null +++ b/vendor/notorm/tests/14-where.phpt @@ -0,0 +1,28 @@ +--TEST-- +WHERE +--FILE-- +application("id", 4), + $software->application("id < ?", 4), + $software->application("id < ?", array(4)), + $software->application("id", array(1, 2)), + $software->application("id", null), + $software->application("id", $software->application()), + $software->application("id < ?", 4)->where("maintainer_id IS NOT NULL"), + $software->application(array("id < ?" => 4, "author_id" => 12)), +) as $result) { + echo implode(", ", array_keys(iterator_to_array($result->order("id")))) . "\n"; // aggregation("GROUP_CONCAT(id)") is not available in all drivers +} +?> +--EXPECTF-- +4 +1, 2, 3 +1, 2, 3 +1, 2 + +1, 2, 3, 4 +1, 3 +3 diff --git a/vendor/notorm/tests/15-multiple.phpt b/vendor/notorm/tests/15-multiple.phpt new file mode 100644 index 0000000..77ddde3 --- /dev/null +++ b/vendor/notorm/tests/15-multiple.phpt @@ -0,0 +1,17 @@ +--TEST-- +Multiple arguments +--FILE-- +application[1]; +foreach ($application->application_tag() + ->select("application_id", "tag_id") + ->order("application_id DESC", "tag_id DESC") +as $application_tag) { + echo "$application_tag[application_id] $application_tag[tag_id]\n"; +} +?> +--EXPECTF-- +1 22 +1 21 diff --git a/vendor/notorm/tests/16-offset.phpt b/vendor/notorm/tests/16-offset.phpt new file mode 100644 index 0000000..a904dd1 --- /dev/null +++ b/vendor/notorm/tests/16-offset.phpt @@ -0,0 +1,23 @@ +--TEST-- +Limit and offset +--FILE-- +application[1]; +foreach ($application->application_tag()->order("tag_id")->limit(1, 1) as $application_tag) { + echo $application_tag->tag["name"] . "\n"; +} +echo "\n"; + +foreach ($software->application() as $application) { + foreach ($application->application_tag()->order("tag_id")->limit(1, 1) as $application_tag) { + echo $application_tag->tag["name"] . "\n"; + } +} +?> +--EXPECTF-- +MySQL + +MySQL +MySQL diff --git a/vendor/notorm/tests/17-transaction.phpt b/vendor/notorm/tests/17-transaction.phpt new file mode 100644 index 0000000..3f66ba0 --- /dev/null +++ b/vendor/notorm/tests/17-transaction.phpt @@ -0,0 +1,15 @@ +--TEST-- +Transactions +--FILE-- +transaction = "BEGIN"; +$software->tag()->insert(array("id" => 99, "name" => "Test")); +echo $software->tag[99] . "\n"; +$software->transaction = "ROLLBACK"; +echo $software->tag[99] . "\n"; +?> +--EXPECTF-- +99 + diff --git a/vendor/notorm/tests/18-union.phpt b/vendor/notorm/tests/18-union.phpt new file mode 100644 index 0000000..8b42b95 --- /dev/null +++ b/vendor/notorm/tests/18-union.phpt @@ -0,0 +1,22 @@ +--TEST-- +Complex UNION +--SKIPIF-- +getAttribute(PDO::ATTR_DRIVER_NAME); +echo (preg_match('~^(sqlite|oci)$~', $driver) ? "Not supported in $driver.\n" : ""); +?> +--FILE-- +application()->select("id")->order("id DESC")->limit(2); +$tags = $software->tag()->select("id")->order("id")->limit(2); +foreach ($applications->union($tags)->order("id DESC") as $row) { + echo "$row[id]\n"; +} +?> +--EXPECTF-- +22 +21 +4 +3 diff --git a/vendor/notorm/tests/19-array-offset.phpt b/vendor/notorm/tests/19-array-offset.phpt new file mode 100644 index 0000000..7381282 --- /dev/null +++ b/vendor/notorm/tests/19-array-offset.phpt @@ -0,0 +1,19 @@ +--TEST-- +Array offset +--FILE-- + "11", + "maintainer_id" => null, +); + +echo $software->application[$where]["id"] . "\n"; + +$applications = $software->application()->order("id"); +echo $applications[$where]["id"] . "\n"; +?> +--EXPECTF-- +2 +2 diff --git a/vendor/notorm/tests/2-detail.phpt b/vendor/notorm/tests/2-detail.phpt new file mode 100644 index 0000000..7ca1fa1 --- /dev/null +++ b/vendor/notorm/tests/2-detail.phpt @@ -0,0 +1,18 @@ +--TEST-- +Single row detail +--FILE-- +application[1]; +foreach ($application as $key => $val) { + echo "$key: $val\n"; +} +?> +--EXPECTF-- +id: 1 +author_id: 11 +maintainer_id: 11 +title: Adminer +web: http://www.adminer.org/ +slogan: Database management in single PHP file diff --git a/vendor/notorm/tests/20-extended.phpt b/vendor/notorm/tests/20-extended.phpt new file mode 100644 index 0000000..2605185 --- /dev/null +++ b/vendor/notorm/tests/20-extended.phpt @@ -0,0 +1,22 @@ +--TEST-- +Extended insert +--SKIPIF-- +getAttribute(PDO::ATTR_DRIVER_NAME); +echo (preg_match('~^(sqlite|oci)$~', $driver) ? "Not supported in $driver.\n" : ""); +?> +--FILE-- +application[3]; +$application->application_tag()->insert(array("tag_id" => 22), array("tag_id" => 23)); +foreach ($application->application_tag()->order("tag_id DESC") as $application_tag) { + echo "$application_tag[application_id] $application_tag[tag_id]\n"; +} +$application->application_tag("tag_id", array(22, 23))->delete(); +?> +--EXPECTF-- +3 23 +3 22 +3 21 diff --git a/vendor/notorm/tests/21-simple-union.phpt b/vendor/notorm/tests/21-simple-union.phpt new file mode 100644 index 0000000..1f82130 --- /dev/null +++ b/vendor/notorm/tests/21-simple-union.phpt @@ -0,0 +1,20 @@ +--TEST-- +Simple UNION +--FILE-- +application()->select("id"); +$tags = $software->tag()->select("id"); +foreach ($applications->union($tags)->order("id DESC") as $row) { + echo "$row[id]\n"; +} +?> +--EXPECTF-- +23 +22 +21 +4 +3 +2 +1 diff --git a/vendor/notorm/tests/22-insert-update.phpt b/vendor/notorm/tests/22-insert-update.phpt new file mode 100644 index 0000000..b42068b --- /dev/null +++ b/vendor/notorm/tests/22-insert-update.phpt @@ -0,0 +1,17 @@ +--TEST-- +INSERT or UPDATE +--FILE-- +application()->insert_update(array("id" => 5), array("author_id" => 12, "title" => "Texy", "web" => "", "slogan" => "$i")) . "\n"; +} +$application = $software->application[5]; +echo $application->application_tag()->insert_update(array("tag_id" => 21), array()) . "\n"; +$software->application("id", 5)->delete(); +?> +--EXPECTF-- +1 +2 +1 diff --git a/vendor/notorm/tests/23-prefix.phpt b/vendor/notorm/tests/23-prefix.phpt new file mode 100644 index 0000000..3105a85 --- /dev/null +++ b/vendor/notorm/tests/23-prefix.phpt @@ -0,0 +1,12 @@ +--TEST-- +Table prefix +--FILE-- +application("author.name", "Jakub Vrana"); +echo "$applications\n"; +?> +--EXPECTF-- +SELECT prefix_application.* FROM prefix_application LEFT JOIN prefix_author AS author ON prefix_application.author_id = author.id WHERE (author.name = 'Jakub Vrana') diff --git a/vendor/notorm/tests/24-lock.phpt b/vendor/notorm/tests/24-lock.phpt new file mode 100644 index 0000000..b2ae4bf --- /dev/null +++ b/vendor/notorm/tests/24-lock.phpt @@ -0,0 +1,10 @@ +--TEST-- +Select locking +--FILE-- +application()->lock() . "\n"; +?> +--EXPECTF-- +SELECT * FROM application FOR UPDATE diff --git a/vendor/notorm/tests/25-backjoin.phpt b/vendor/notorm/tests/25-backjoin.phpt new file mode 100644 index 0000000..e4c9d34 --- /dev/null +++ b/vendor/notorm/tests/25-backjoin.phpt @@ -0,0 +1,13 @@ +--TEST-- +Backwards join +--FILE-- +author()->select("author.*, COUNT(DISTINCT application:application_tag:tag_id) AS tags")->group("author.id")->order("tags DESC") as $autor) { + echo "$autor[name]: $autor[tags]\n"; +} +?> +--EXPECTF-- +Jakub Vrana: 3 +David Grudl: 2 diff --git a/vendor/notorm/tests/26-in.phpt b/vendor/notorm/tests/26-in.phpt new file mode 100644 index 0000000..78327d9 --- /dev/null +++ b/vendor/notorm/tests/26-in.phpt @@ -0,0 +1,16 @@ +--TEST-- +IN operator +--FILE-- +application("maintainer_id", array())->count("*") . "\n"; +echo $software->application("maintainer_id", array(11))->count("*") . "\n"; +echo $software->application("NOT maintainer_id", array(11))->count("*") . "\n"; +echo $software->application("NOT maintainer_id", array())->count("*") . "\n"; +?> +--EXPECTF-- +0 +1 +2 +3 diff --git a/vendor/notorm/tests/27-in-multi.phpt b/vendor/notorm/tests/27-in-multi.phpt new file mode 100644 index 0000000..c23b57b --- /dev/null +++ b/vendor/notorm/tests/27-in-multi.phpt @@ -0,0 +1,19 @@ +--TEST-- +IN operator with MultiResult +--FILE-- +author()->order("id") as $author) { + foreach ($software->application_tag("application_id", $author->application())->order("application_id, tag_id") as $application_tag) { + echo "$author: $application_tag[application_id]: $application_tag[tag_id]\n"; + } +} +?> +--EXPECTF-- +11: 1: 21 +11: 1: 22 +11: 2: 23 +12: 3: 21 +12: 4: 21 +12: 4: 22 diff --git a/vendor/notorm/tests/28-literal.phpt b/vendor/notorm/tests/28-literal.phpt new file mode 100644 index 0000000..d19c4f6 --- /dev/null +++ b/vendor/notorm/tests/28-literal.phpt @@ -0,0 +1,12 @@ +--TEST-- +Literal value with parameters +--FILE-- +author()->select(new NotORM_Literal("? + ?", 1, 2))->fetch() as $val) { + echo "$val\n"; +} +?> +--EXPECTF-- +3 diff --git a/vendor/notorm/tests/29-row-set.phpt b/vendor/notorm/tests/29-row-set.phpt new file mode 100644 index 0000000..b13f2d6 --- /dev/null +++ b/vendor/notorm/tests/29-row-set.phpt @@ -0,0 +1,13 @@ +--TEST-- +Update row through property +--FILE-- +application[1]; +$application->author = $software->author[12]; +echo $application->update() . "\n"; +$application->update(array("author_id" => 11)); +?> +--EXPECTF-- +1 diff --git a/vendor/notorm/tests/3-search-order.phpt b/vendor/notorm/tests/3-search-order.phpt new file mode 100644 index 0000000..b558274 --- /dev/null +++ b/vendor/notorm/tests/3-search-order.phpt @@ -0,0 +1,14 @@ +--TEST-- +Search and order items +--FILE-- +application("web LIKE ?", "http://%")->order("title")->limit(3) as $application) { + echo "$application[title]\n"; +} +?> +--EXPECTF-- +Adminer +Dibi +JUSH diff --git a/vendor/notorm/tests/30-rowclass.phpt b/vendor/notorm/tests/30-rowclass.phpt new file mode 100644 index 0000000..2352131 --- /dev/null +++ b/vendor/notorm/tests/30-rowclass.phpt @@ -0,0 +1,29 @@ +--TEST-- +Custom row class +--FILE-- +rowClass = 'TestRow'; + +$application = $software->application[1]; +echo "$application[test_title]\n"; +echo $application->author["test_name"] . "\n"; + +$software->rowClass = 'NotORM_Row'; +?> +--EXPECTF-- +Adminer +Jakub Vrana diff --git a/vendor/notorm/tests/31-datetime.phpt b/vendor/notorm/tests/31-datetime.phpt new file mode 100644 index 0000000..40fe5a9 --- /dev/null +++ b/vendor/notorm/tests/31-datetime.phpt @@ -0,0 +1,21 @@ +--TEST-- +DateTime processing +--FILE-- +application()->insert(array( + "id" => 5, + "author_id" => 11, + "title" => $date, + "slogan" => new NotORM_Literal("?", $date), +)); + +$application = $software->application()->where("title = ?", $date)->fetch(); +echo "$application[slogan]\n"; +$application->delete(); +?> +--EXPECTF-- +2011-08-30 00:00:00 diff --git a/vendor/notorm/tests/32-in-null.phpt b/vendor/notorm/tests/32-in-null.phpt new file mode 100644 index 0000000..125b363 --- /dev/null +++ b/vendor/notorm/tests/32-in-null.phpt @@ -0,0 +1,13 @@ +--TEST-- +IN with NULL value +--FILE-- +application("maintainer_id", array(11, null)) as $application) { + echo "$application[id]\n"; +} +?> +--EXPECTF-- +1 +2 diff --git a/vendor/notorm/tests/33-structure.phpt b/vendor/notorm/tests/33-structure.phpt new file mode 100644 index 0000000..0864448 --- /dev/null +++ b/vendor/notorm/tests/33-structure.phpt @@ -0,0 +1,25 @@ +--TEST-- +Structure for non-conventional column +--FILE-- +application[1]->maintainer; +echo $maintainer['name'] . "\n"; +foreach ($maintainer->application()->via('maintainer_id') as $application) { + echo "\t$application[title]\n"; +} +?> +--EXPECTF-- +Jakub Vrana + Adminer diff --git a/vendor/notorm/tests/34-update-primary.phpt b/vendor/notorm/tests/34-update-primary.phpt new file mode 100644 index 0000000..5f808b6 --- /dev/null +++ b/vendor/notorm/tests/34-update-primary.phpt @@ -0,0 +1,18 @@ +--TEST-- +Update primary key of a row +--FILE-- +tag()->insert(array('id' => 24, 'name' => 'HTML')); +echo "$application[id]\n"; +$application['id'] = 25; +echo "$application[id]\n"; +echo $application->update() . "\n"; +echo $application->delete() . "\n"; +?> +--EXPECTF-- +24 +25 +1 +1 diff --git a/vendor/notorm/tests/35-multiresult-loop.phpt b/vendor/notorm/tests/35-multiresult-loop.phpt new file mode 100644 index 0000000..44849a6 --- /dev/null +++ b/vendor/notorm/tests/35-multiresult-loop.phpt @@ -0,0 +1,16 @@ +--TEST-- +Using the same MultiResult several times +--FILE-- +application[1]; +for ($i = 0; $i < 4; $i++) { + echo count($application->application_tag()) . "\n"; +} +?> +--EXPECTF-- +2 +2 +2 +2 diff --git a/vendor/notorm/tests/36-and.phpt b/vendor/notorm/tests/36-and.phpt new file mode 100644 index 0000000..7d7a86c --- /dev/null +++ b/vendor/notorm/tests/36-and.phpt @@ -0,0 +1,12 @@ +--TEST-- +Calling and() +--FILE-- +application("author_id", 11)->and("maintainer_id", 11) as $application) { + echo "$application[title]\n"; +} +?> +--EXPECTF-- +Adminer diff --git a/vendor/notorm/tests/37-or.phpt b/vendor/notorm/tests/37-or.phpt new file mode 100644 index 0000000..76abc52 --- /dev/null +++ b/vendor/notorm/tests/37-or.phpt @@ -0,0 +1,14 @@ +--TEST-- +Calling or() +--FILE-- +application("author_id", 12)->or("maintainer_id", 11)->order("title") as $application) { + echo "$application[title]\n"; +} +?> +--EXPECTF-- +Adminer +Dibi +Nette diff --git a/vendor/notorm/tests/38-parens.phpt b/vendor/notorm/tests/38-parens.phpt new file mode 100644 index 0000000..d6f13c4 --- /dev/null +++ b/vendor/notorm/tests/38-parens.phpt @@ -0,0 +1,19 @@ +--TEST-- +Calling or() +--FILE-- +application() + ->where("(author_id", 11)->and("maintainer_id", 11)->where(")") + ->or("(author_id", 12)->and("maintainer_id", 12)->where(")") +; + +foreach ($applications->order("title") as $application) { + echo "$application[title]\n"; +} +?> +--EXPECTF-- +Adminer +Dibi +Nette diff --git a/vendor/notorm/tests/4-findone.phpt b/vendor/notorm/tests/4-findone.phpt new file mode 100644 index 0000000..136cd6b --- /dev/null +++ b/vendor/notorm/tests/4-findone.phpt @@ -0,0 +1,15 @@ +--TEST-- +Find one item by title +--FILE-- +application("title", "Adminer")->fetch(); +foreach ($application->application_tag("tag_id", 21) as $application_tag) { + echo $application_tag->tag["name"] . "\n"; +} +echo $software->application("title", "Adminer")->fetch("slogan") . "\n"; +?> +--EXPECTF-- +PHP +Database management in single PHP file diff --git a/vendor/notorm/tests/5-tostring.phpt b/vendor/notorm/tests/5-tostring.phpt new file mode 100644 index 0000000..967bb79 --- /dev/null +++ b/vendor/notorm/tests/5-tostring.phpt @@ -0,0 +1,15 @@ +--TEST-- +Calling __toString() +--FILE-- +application() as $application) { + echo "$application\n"; +} +?> +--EXPECTF-- +1 +2 +3 +4 diff --git a/vendor/notorm/tests/6-aggregation.phpt b/vendor/notorm/tests/6-aggregation.phpt new file mode 100644 index 0000000..3d234d6 --- /dev/null +++ b/vendor/notorm/tests/6-aggregation.phpt @@ -0,0 +1,19 @@ +--TEST-- +Aggregation functions +--FILE-- +application()->count("*"); +echo "$count applications\n"; +foreach ($software->application() as $application) { + $count = $application->application_tag()->count("*"); + echo "$application[title]: $count tag(s)\n"; +} +?> +--EXPECTF-- +4 applications +Adminer: 2 tag(s) +JUSH: 1 tag(s) +Nette: 1 tag(s) +Dibi: 2 tag(s) diff --git a/vendor/notorm/tests/7-subquery.phpt b/vendor/notorm/tests/7-subquery.phpt new file mode 100644 index 0000000..b0abc1a --- /dev/null +++ b/vendor/notorm/tests/7-subquery.phpt @@ -0,0 +1,16 @@ +--TEST-- +Subqueries +--FILE-- +author("born", null); // authors with unknown date of born +foreach ($software->application("author_id", $unknownBorn) as $application) { // their applications + echo "$application[title]\n"; +} +?> +--EXPECTF-- +Adminer +JUSH +Nette +Dibi diff --git a/vendor/notorm/tests/8-discovery.phpt b/vendor/notorm/tests/8-discovery.phpt new file mode 100644 index 0000000..d113dde --- /dev/null +++ b/vendor/notorm/tests/8-discovery.phpt @@ -0,0 +1,25 @@ +--TEST-- +Discovery test +--FILE-- +application() as $application) { + echo "$application[title] (" . $application->author_id["name"] . ")\n"; + foreach ($application->application_tag() as $application_tag) { + echo "\t" . $application_tag->tag_id["name"] . "\n"; + } +} +?> +--EXPECTF-- +Adminer (Jakub Vrana) + PHP + MySQL +JUSH (Jakub Vrana) + JavaScript +Nette (David Grudl) + PHP +Dibi (David Grudl) + PHP + MySQL diff --git a/vendor/notorm/tests/9-cache.phpt b/vendor/notorm/tests/9-cache.phpt new file mode 100644 index 0000000..86532b4 --- /dev/null +++ b/vendor/notorm/tests/9-cache.phpt @@ -0,0 +1,31 @@ +--TEST-- +Session cache +--FILE-- +application(); +$application = $applications->fetch(); +$application["title"]; +$application->author["name"]; +echo "$applications\n"; // get all columns with no cache +$applications->__destruct(); + +$applications = $cache->application(); +$application = $applications->fetch(); +echo "$applications\n"; // get only title and author_id +$application["slogan"]; // script changed and now we want also slogan +echo "$applications\n"; // all columns must have been retrieved to get slogan +$applications->__destruct(); + +$applications = $cache->application(); +$applications->fetch(); +echo "$applications\n"; // next time, get only title, author_id and slogan +?> +--EXPECTF-- +SELECT * FROM application +SELECT id, title, author_id FROM application +SELECT * FROM application +SELECT id, title, author_id, slogan FROM application diff --git a/vendor/notorm/tests/connect.inc.php b/vendor/notorm/tests/connect.inc.php new file mode 100644 index 0000000..1505bdd --- /dev/null +++ b/vendor/notorm/tests/connect.inc.php @@ -0,0 +1,9 @@ +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); +$connection->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER); +$software = new NotORM($connection); +//~ $software->debug = true; diff --git a/vendor/notorm/tests/run-tests.php b/vendor/notorm/tests/run-tests.php new file mode 100644 index 0000000..d2f689c --- /dev/null +++ b/vendor/notorm/tests/run-tests.php @@ -0,0 +1,18 @@ +