Browse Source

PHPixie framework

Roman Tsiupa 12 years ago
parent
commit
a96c6989d5
84 changed files with 8146 additions and 0 deletions
  1. 16 0
      php-phpixie/assets/config/db.php
  2. 8 0
      php-phpixie/assets/config/routes.php
  3. 12 0
      php-phpixie/assets/views/fortunes.php
  4. 78 0
      php-phpixie/classes/App/Controller/Benchmark.php
  5. 0 0
      php-phpixie/classes/App/Model/.gitignore
  6. 7 0
      php-phpixie/classes/App/Model/Fortune.php
  7. 7 0
      php-phpixie/classes/App/Model/World.php
  8. 20 0
      php-phpixie/classes/App/Pixie.php
  9. 7 0
      php-phpixie/composer.json
  10. 7 0
      php-phpixie/vendor/autoload.php
  11. 246 0
      php-phpixie/vendor/composer/ClassLoader.php
  12. 35 0
      php-phpixie/vendor/composer/autoload_classmap.php
  13. 10 0
      php-phpixie/vendor/composer/autoload_namespaces.php
  14. 43 0
      php-phpixie/vendor/composer/autoload_real.php
  15. 150 0
      php-phpixie/vendor/composer/installed.json
  16. 4 0
      php-phpixie/vendor/phpixie/core/README.md
  17. 126 0
      php-phpixie/vendor/phpixie/core/assets/views/debug.php
  18. 166 0
      php-phpixie/vendor/phpixie/core/classes/PHPixie/Config.php
  19. 109 0
      php-phpixie/vendor/phpixie/core/classes/PHPixie/Controller.php
  20. 154 0
      php-phpixie/vendor/phpixie/core/classes/PHPixie/Debug.php
  21. 250 0
      php-phpixie/vendor/phpixie/core/classes/PHPixie/Pixie.php
  22. 200 0
      php-phpixie/vendor/phpixie/core/classes/PHPixie/Request.php
  23. 71 0
      php-phpixie/vendor/phpixie/core/classes/PHPixie/Response.php
  24. 98 0
      php-phpixie/vendor/phpixie/core/classes/PHPixie/Route.php
  25. 130 0
      php-phpixie/vendor/phpixie/core/classes/PHPixie/Router.php
  26. 119 0
      php-phpixie/vendor/phpixie/core/classes/PHPixie/Session.php
  27. 106 0
      php-phpixie/vendor/phpixie/core/classes/PHPixie/View.php
  28. 26 0
      php-phpixie/vendor/phpixie/core/composer.json
  29. 10 0
      php-phpixie/vendor/phpixie/core/tests/bootstrap.php
  30. 108 0
      php-phpixie/vendor/phpixie/core/tests/configTest.php
  31. 58 0
      php-phpixie/vendor/phpixie/core/tests/controllerTest.php
  32. 1 0
      php-phpixie/vendor/phpixie/core/tests/phpunit.xml
  33. 105 0
      php-phpixie/vendor/phpixie/core/tests/pixieTest.php
  34. 158 0
      php-phpixie/vendor/phpixie/core/tests/requestTest.php
  35. 66 0
      php-phpixie/vendor/phpixie/core/tests/responseTest.php
  36. 43 0
      php-phpixie/vendor/phpixie/core/tests/routeTest.php
  37. 132 0
      php-phpixie/vendor/phpixie/core/tests/routerTest.php
  38. 91 0
      php-phpixie/vendor/phpixie/core/tests/sessionTest.php
  39. 54 0
      php-phpixie/vendor/phpixie/core/tests/viewTest.php
  40. 4 0
      php-phpixie/vendor/phpixie/db/README.md
  41. 129 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB.php
  42. 92 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Connection.php
  43. 35 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Expression.php
  44. 123 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Mysql/Connection.php
  45. 12 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Mysql/Query.php
  46. 57 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Mysql/Result.php
  47. 132 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/PDO/Connection.php
  48. 393 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/PDO/Query.php
  49. 57 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/PDO/Result.php
  50. 445 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Query.php
  51. 113 0
      php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Result.php
  52. 26 0
      php-phpixie/vendor/phpixie/db/composer.json
  53. 10 0
      php-phpixie/vendor/phpixie/db/tests/bootstrap.php
  54. 81 0
      php-phpixie/vendor/phpixie/db/tests/db/dbTest.php
  55. 41 0
      php-phpixie/vendor/phpixie/db/tests/db/expressionTest.php
  56. 25 0
      php-phpixie/vendor/phpixie/db/tests/db/mysql/connectionTest.php
  57. 207 0
      php-phpixie/vendor/phpixie/db/tests/db/mysql/queryTest.php
  58. 132 0
      php-phpixie/vendor/phpixie/db/tests/db/mysql/resultTest.php
  59. 127 0
      php-phpixie/vendor/phpixie/db/tests/db/pdo/connectionTest.php
  60. 264 0
      php-phpixie/vendor/phpixie/db/tests/db/pdo/queryTest.php
  61. 134 0
      php-phpixie/vendor/phpixie/db/tests/db/pdo/resultTest.php
  62. 1 0
      php-phpixie/vendor/phpixie/db/tests/phpunit.xml
  63. 4 0
      php-phpixie/vendor/phpixie/orm/README.md
  64. 79 0
      php-phpixie/vendor/phpixie/orm/classes/PHPixie/ORM.php
  65. 34 0
      php-phpixie/vendor/phpixie/orm/classes/PHPixie/ORM/Extension.php
  66. 290 0
      php-phpixie/vendor/phpixie/orm/classes/PHPixie/ORM/Extension/Nested.php
  67. 846 0
      php-phpixie/vendor/phpixie/orm/classes/PHPixie/ORM/Model.php
  68. 236 0
      php-phpixie/vendor/phpixie/orm/classes/PHPixie/ORM/Result.php
  69. 26 0
      php-phpixie/vendor/phpixie/orm/composer.json
  70. 10 0
      php-phpixie/vendor/phpixie/orm/tests/bootstrap.php
  71. 6 0
      php-phpixie/vendor/phpixie/orm/tests/files/extension.php
  72. 23 0
      php-phpixie/vendor/phpixie/orm/tests/files/fairy_orm.php
  73. 5 0
      php-phpixie/vendor/phpixie/orm/tests/files/namespaced_orm.php
  74. 11 0
      php-phpixie/vendor/phpixie/orm/tests/files/nested_orm.php
  75. 23 0
      php-phpixie/vendor/phpixie/orm/tests/files/stub_orm.php
  76. 39 0
      php-phpixie/vendor/phpixie/orm/tests/files/test_result.php
  77. 13 0
      php-phpixie/vendor/phpixie/orm/tests/files/tree_orm.php
  78. 205 0
      php-phpixie/vendor/phpixie/orm/tests/orm/extension/nestedTest.php
  79. 370 0
      php-phpixie/vendor/phpixie/orm/tests/orm/modelTest.php
  80. 76 0
      php-phpixie/vendor/phpixie/orm/tests/orm/ormTest.php
  81. 158 0
      php-phpixie/vendor/phpixie/orm/tests/orm/resultTest.php
  82. 1 0
      php-phpixie/vendor/phpixie/orm/tests/phpunit.xml
  83. 9 0
      php-phpixie/web/.htaccess
  84. 11 0
      php-phpixie/web/index.php

+ 16 - 0
php-phpixie/assets/config/db.php

@@ -0,0 +1,16 @@
+<?php
+
+return array(
+	'default' => array(
+		'user'=>'benchmarkdbuser',
+		'password' => 'benchmarkdbpass',
+		'driver' => 'mysql',
+		
+		//'Connection' is required if you use the PDO driver
+		'connection'=>'mysql:host=localhost;dbname=hello_world',
+		
+		// 'db' and 'host' are required if you use Mysqli driver
+		'db' => 'hello_world',
+		'host'=>'localhost'
+	)
+);

+ 8 - 0
php-phpixie/assets/config/routes.php

@@ -0,0 +1,8 @@
+<?php
+return array(
+	'default' => array('/<action>', array(
+					'controller' => 'Benchmark',
+					'action' => 'index'
+					)
+				),
+);

+ 12 - 0
php-phpixie/assets/views/fortunes.php

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<head><title>Fortunes</title></head>
+<body>
+<table>
+<tr><th>id</th><th>message</th></tr>
+<?php foreach($fortunes as $fortune):?>
+<tr><td><?php echo $fortune->id?></td><td><?php echo htmlentities($fortune->message)?></td></tr>
+<?php endforeach;?>
+</table>
+</body>
+</html>

+ 78 - 0
php-phpixie/classes/App/Controller/Benchmark.php

@@ -0,0 +1,78 @@
+<?php
+namespace App\Controller;
+
+class Benchmark extends \PHPixie\Controller {
+
+	public function action_json(){
+		$this->response->add_header("Content-Type: application/json");
+		$this->response-> body = json_encode(array('message' => 'Hello, World!'));
+	}
+	
+	public function action_db() {
+		$this->response->add_header("Content-Type: application/json");
+		$this->response->body = json_encode($this->fetch_random_world()->as_array());
+	}
+	
+	public function action_queries() {
+		$this->response->add_header("Content-Type: application/json");
+		$n = (int)$this->request->get('queries', 1);
+		if ($n < 1)
+			$n = 1;
+		if ($n > 500)
+			$n = 500;
+		$res = array();
+		for ($i = 0; $i < $n; $i++)
+			$res[] = $this->fetch_random_world()->as_array();
+		$this->response->body = json_encode($res);
+	}
+	
+	public function action_fortunes() {
+		$fortunes = $this->pixie-> orm->get('fortune')->find_all()->as_array();
+		$fortune = $this->pixie->orm->get('fortune');
+		$fortune->id = 0;
+		$fortune->message = 'Additional fortune added at request time.';
+		$fortunes[] = $fortune;
+		
+		usort($fortunes, function($a, $b) { 
+			$am = $a->message;
+			$bm = $b->message;
+			if ($am==$bm) return 0;
+			return ($am<$bm)?-1:1;
+		} );
+		
+		$view = $this->pixie->view('fortunes');
+		$view->fortunes = $fortunes;
+		$this->response->body = $view->render();
+		
+	}
+	
+	public function action_updates(){
+		$this->response->add_header("Content-Type: application/json");
+		$n = (int)$this->request->get('queries', 1);
+		if ($n < 1)
+			$n = 1;
+		if ($n > 500)
+			$n = 500;
+		$res = array();
+		for ($i = 0; $i < $n; $i++) {
+			$world = $this->fetch_random_world();
+			$world->randomNumber = rand(1, 10000);
+			$world->save();
+			$res[]=$world->as_array();
+		}
+		$this->response->body = json_encode($res);
+	}
+	
+	public function action_plaintext() {
+		$this->response-> add_header("Content-Type: application/json");
+		$this->response->body = "Hello, World!";
+	}
+	
+	protected function fetch_random_world() {
+		return $this->pixie->orm->get('world')
+				->where('id', rand(1, 10000))
+				->find();
+	}
+	
+	
+}

+ 0 - 0
php-phpixie/classes/App/Model/.gitignore


+ 7 - 0
php-phpixie/classes/App/Model/Fortune.php

@@ -0,0 +1,7 @@
+<?php
+
+namespace App\Model;
+
+class Fortune extends \PHPixie\ORM\Model{
+	public $table = 'Fortune';
+}

+ 7 - 0
php-phpixie/classes/App/Model/World.php

@@ -0,0 +1,7 @@
+<?php
+
+namespace App\Model;
+
+class World extends \PHPixie\ORM\Model{
+	public $table = 'World';
+}

+ 20 - 0
php-phpixie/classes/App/Pixie.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace App;
+
+/**
+ * Pixie dependency container
+ *
+ * @property-read \PHPixie\DB $db Database module
+ * @property-read \PHPixie\ORM $orm ORM module
+ */
+class Pixie extends \PHPixie\Pixie {
+	protected $modules = array(
+		'db' => '\PHPixie\DB',
+		'orm' => '\PHPixie\ORM'
+	);
+	
+	protected function after_bootstrap(){
+		//Whatever code you want to run after bootstrap is done.		
+	}
+}

+ 7 - 0
php-phpixie/composer.json

@@ -0,0 +1,7 @@
+{
+"require": {
+	"phpixie/core": "2.*@dev",
+	"phpixie/db": "2.*@dev",
+	"phpixie/orm": "2.*@dev"
+    }	
+}

+ 7 - 0
php-phpixie/vendor/autoload.php

@@ -0,0 +1,7 @@
+<?php
+
+// autoload.php generated by Composer
+
+require_once __DIR__ . '/composer' . '/autoload_real.php';
+
+return ComposerAutoloaderInit1b6a9162cab34b0e1ddecb1e4d71f50a::getLoader();

+ 246 - 0
php-phpixie/vendor/composer/ClassLoader.php

@@ -0,0 +1,246 @@
+<?php
+
+/*
+ * This file is part of Composer.
+ *
+ * (c) Nils Adermann <[email protected]>
+ *     Jordi Boggiano <[email protected]>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Autoload;
+
+/**
+ * ClassLoader implements a PSR-0 class loader
+ *
+ * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
+ *
+ *     $loader = new \Composer\Autoload\ClassLoader();
+ *
+ *     // register classes with namespaces
+ *     $loader->add('Symfony\Component', __DIR__.'/component');
+ *     $loader->add('Symfony',           __DIR__.'/framework');
+ *
+ *     // activate the autoloader
+ *     $loader->register();
+ *
+ *     // to enable searching the include path (eg. for PEAR packages)
+ *     $loader->setUseIncludePath(true);
+ *
+ * In this example, if you try to use a class in the Symfony\Component
+ * namespace or one of its children (Symfony\Component\Console for instance),
+ * the autoloader will first look for the class under the component/
+ * directory, and it will then fallback to the framework/ directory if not
+ * found before giving up.
+ *
+ * This class is loosely based on the Symfony UniversalClassLoader.
+ *
+ * @author Fabien Potencier <[email protected]>
+ * @author Jordi Boggiano <[email protected]>
+ */
+class ClassLoader
+{
+    private $prefixes = array();
+    private $fallbackDirs = array();
+    private $useIncludePath = false;
+    private $classMap = array();
+
+    public function getPrefixes()
+    {
+        return call_user_func_array('array_merge', $this->prefixes);
+    }
+
+    public function getFallbackDirs()
+    {
+        return $this->fallbackDirs;
+    }
+
+    public function getClassMap()
+    {
+        return $this->classMap;
+    }
+
+    /**
+     * @param array $classMap Class to filename map
+     */
+    public function addClassMap(array $classMap)
+    {
+        if ($this->classMap) {
+            $this->classMap = array_merge($this->classMap, $classMap);
+        } else {
+            $this->classMap = $classMap;
+        }
+    }
+
+    /**
+     * Registers a set of classes, merging with any others previously set.
+     *
+     * @param string       $prefix  The classes prefix
+     * @param array|string $paths   The location(s) of the classes
+     * @param bool         $prepend Prepend the location(s)
+     */
+    public function add($prefix, $paths, $prepend = false)
+    {
+        if (!$prefix) {
+            if ($prepend) {
+                $this->fallbackDirs = array_merge(
+                    (array) $paths,
+                    $this->fallbackDirs
+                );
+            } else {
+                $this->fallbackDirs = array_merge(
+                    $this->fallbackDirs,
+                    (array) $paths
+                );
+            }
+
+            return;
+        }
+
+        $first = $prefix[0];
+        if (!isset($this->prefixes[$first][$prefix])) {
+            $this->prefixes[$first][$prefix] = (array) $paths;
+
+            return;
+        }
+        if ($prepend) {
+            $this->prefixes[$first][$prefix] = array_merge(
+                (array) $paths,
+                $this->prefixes[$first][$prefix]
+            );
+        } else {
+            $this->prefixes[$first][$prefix] = array_merge(
+                $this->prefixes[$first][$prefix],
+                (array) $paths
+            );
+        }
+    }
+
+    /**
+     * Registers a set of classes, replacing any others previously set.
+     *
+     * @param string       $prefix  The classes prefix
+     * @param array|string $paths   The location(s) of the classes
+     */
+    public function set($prefix, $paths)
+    {
+        if (!$prefix) {
+            $this->fallbackDirs = (array) $paths;
+
+            return;
+        }
+        $this->prefixes[substr($prefix, 0, 1)][$prefix] = (array) $paths;
+    }
+
+    /**
+     * Turns on searching the include path for class files.
+     *
+     * @param bool $useIncludePath
+     */
+    public function setUseIncludePath($useIncludePath)
+    {
+        $this->useIncludePath = $useIncludePath;
+    }
+
+    /**
+     * Can be used to check if the autoloader uses the include path to check
+     * for classes.
+     *
+     * @return bool
+     */
+    public function getUseIncludePath()
+    {
+        return $this->useIncludePath;
+    }
+
+    /**
+     * Registers this instance as an autoloader.
+     *
+     * @param bool $prepend Whether to prepend the autoloader or not
+     */
+    public function register($prepend = false)
+    {
+        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
+    }
+
+    /**
+     * Unregisters this instance as an autoloader.
+     */
+    public function unregister()
+    {
+        spl_autoload_unregister(array($this, 'loadClass'));
+    }
+
+    /**
+     * Loads the given class or interface.
+     *
+     * @param  string    $class The name of the class
+     * @return bool|null True if loaded, null otherwise
+     */
+    public function loadClass($class)
+    {
+        if ($file = $this->findFile($class)) {
+            include $file;
+
+            return true;
+        }
+    }
+
+    /**
+     * Finds the path to the file where the class is defined.
+     *
+     * @param string $class The name of the class
+     *
+     * @return string|false The path if found, false otherwise
+     */
+    public function findFile($class)
+    {
+        // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
+        if ('\\' == $class[0]) {
+            $class = substr($class, 1);
+        }
+
+        if (isset($this->classMap[$class])) {
+            return $this->classMap[$class];
+        }
+
+        if (false !== $pos = strrpos($class, '\\')) {
+            // namespaced class name
+            $classPath = strtr(substr($class, 0, $pos), '\\', DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
+            $className = substr($class, $pos + 1);
+        } else {
+            // PEAR-like class name
+            $classPath = null;
+            $className = $class;
+        }
+
+        $classPath .= strtr($className, '_', DIRECTORY_SEPARATOR) . '.php';
+
+        $first = $class[0];
+        if (isset($this->prefixes[$first])) {
+            foreach ($this->prefixes[$first] as $prefix => $dirs) {
+                if (0 === strpos($class, $prefix)) {
+                    foreach ($dirs as $dir) {
+                        if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
+                            return $dir . DIRECTORY_SEPARATOR . $classPath;
+                        }
+                    }
+                }
+            }
+        }
+
+        foreach ($this->fallbackDirs as $dir) {
+            if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
+                return $dir . DIRECTORY_SEPARATOR . $classPath;
+            }
+        }
+
+        if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
+            return $file;
+        }
+
+        return $this->classMap[$class] = false;
+    }
+}

+ 35 - 0
php-phpixie/vendor/composer/autoload_classmap.php

@@ -0,0 +1,35 @@
+<?php
+
+// autoload_classmap.php generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+    'PHPixie\\Config' => $vendorDir . '/phpixie/core/classes/PHPixie/Config.php',
+    'PHPixie\\Controller' => $vendorDir . '/phpixie/core/classes/PHPixie/Controller.php',
+    'PHPixie\\DB' => $vendorDir . '/phpixie/db/classes/PHPixie/DB.php',
+    'PHPixie\\DB\\Connection' => $vendorDir . '/phpixie/db/classes/PHPixie/DB/Connection.php',
+    'PHPixie\\DB\\Expression' => $vendorDir . '/phpixie/db/classes/PHPixie/DB/Expression.php',
+    'PHPixie\\DB\\Mysql\\Connection' => $vendorDir . '/phpixie/db/classes/PHPixie/DB/Mysql/Connection.php',
+    'PHPixie\\DB\\Mysql\\Query' => $vendorDir . '/phpixie/db/classes/PHPixie/DB/Mysql/Query.php',
+    'PHPixie\\DB\\Mysql\\Result' => $vendorDir . '/phpixie/db/classes/PHPixie/DB/Mysql/Result.php',
+    'PHPixie\\DB\\PDO\\Connection' => $vendorDir . '/phpixie/db/classes/PHPixie/DB/PDO/Connection.php',
+    'PHPixie\\DB\\PDO\\Query' => $vendorDir . '/phpixie/db/classes/PHPixie/DB/PDO/Query.php',
+    'PHPixie\\DB\\PDO\\Result' => $vendorDir . '/phpixie/db/classes/PHPixie/DB/PDO/Result.php',
+    'PHPixie\\DB\\Query' => $vendorDir . '/phpixie/db/classes/PHPixie/DB/Query.php',
+    'PHPixie\\DB\\Result' => $vendorDir . '/phpixie/db/classes/PHPixie/DB/Result.php',
+    'PHPixie\\Debug' => $vendorDir . '/phpixie/core/classes/PHPixie/Debug.php',
+    'PHPixie\\ORM' => $vendorDir . '/phpixie/orm/classes/PHPixie/ORM.php',
+    'PHPixie\\ORM\\Extension' => $vendorDir . '/phpixie/orm/classes/PHPixie/ORM/Extension.php',
+    'PHPixie\\ORM\\Extension\\Nested' => $vendorDir . '/phpixie/orm/classes/PHPixie/ORM/Extension/Nested.php',
+    'PHPixie\\ORM\\Model' => $vendorDir . '/phpixie/orm/classes/PHPixie/ORM/Model.php',
+    'PHPixie\\ORM\\Result' => $vendorDir . '/phpixie/orm/classes/PHPixie/ORM/Result.php',
+    'PHPixie\\Pixie' => $vendorDir . '/phpixie/core/classes/PHPixie/Pixie.php',
+    'PHPixie\\Request' => $vendorDir . '/phpixie/core/classes/PHPixie/Request.php',
+    'PHPixie\\Response' => $vendorDir . '/phpixie/core/classes/PHPixie/Response.php',
+    'PHPixie\\Route' => $vendorDir . '/phpixie/core/classes/PHPixie/Route.php',
+    'PHPixie\\Router' => $vendorDir . '/phpixie/core/classes/PHPixie/Router.php',
+    'PHPixie\\Session' => $vendorDir . '/phpixie/core/classes/PHPixie/Session.php',
+    'PHPixie\\View' => $vendorDir . '/phpixie/core/classes/PHPixie/View.php',
+);

+ 10 - 0
php-phpixie/vendor/composer/autoload_namespaces.php

@@ -0,0 +1,10 @@
+<?php
+
+// autoload_namespaces.php generated by Composer
+
+$vendorDir = dirname(dirname(__FILE__));
+$baseDir = dirname($vendorDir);
+
+return array(
+    'PHPixie' => array($vendorDir . '/phpixie/core/classes', $vendorDir . '/phpixie/db/classes', $vendorDir . '/phpixie/orm/classes'),
+);

+ 43 - 0
php-phpixie/vendor/composer/autoload_real.php

@@ -0,0 +1,43 @@
+<?php
+
+// autoload_real.php generated by Composer
+
+class ComposerAutoloaderInit1b6a9162cab34b0e1ddecb1e4d71f50a
+{
+    private static $loader;
+
+    public static function loadClassLoader($class)
+    {
+        if ('Composer\Autoload\ClassLoader' === $class) {
+            require __DIR__ . '/ClassLoader.php';
+        }
+    }
+
+    public static function getLoader()
+    {
+        if (null !== self::$loader) {
+            return self::$loader;
+        }
+
+        spl_autoload_register(array('ComposerAutoloaderInit1b6a9162cab34b0e1ddecb1e4d71f50a', 'loadClassLoader'), true, true);
+        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
+        spl_autoload_unregister(array('ComposerAutoloaderInit1b6a9162cab34b0e1ddecb1e4d71f50a', 'loadClassLoader'));
+
+        $vendorDir = dirname(__DIR__);
+        $baseDir = dirname($vendorDir);
+
+        $map = require __DIR__ . '/autoload_namespaces.php';
+        foreach ($map as $namespace => $path) {
+            $loader->set($namespace, $path);
+        }
+
+        $classMap = require __DIR__ . '/autoload_classmap.php';
+        if ($classMap) {
+            $loader->addClassMap($classMap);
+        }
+
+        $loader->register(true);
+
+        return $loader;
+    }
+}

+ 150 - 0
php-phpixie/vendor/composer/installed.json

@@ -0,0 +1,150 @@
+[
+    {
+        "name": "phpixie/core",
+        "version": "dev-master",
+        "version_normalized": "9999999-dev",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/dracony/PHPixie-Core.git",
+            "reference": "387a6d25ca3c73ff8503263db75c7664a69975ca"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/dracony/PHPixie-Core/zipball/387a6d25ca3c73ff8503263db75c7664a69975ca",
+            "reference": "387a6d25ca3c73ff8503263db75c7664a69975ca",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.0"
+        },
+        "time": "2013-05-16 08:42:00",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "2.*-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "PHPixie": "classes/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "BSD"
+        ],
+        "authors": [
+            {
+                "name": "Roman Tsiupa",
+                "email": "[email protected]",
+                "homepage": "http://dracony.org"
+            }
+        ],
+        "description": "PHPixie Framework",
+        "homepage": "http://phpixie.com",
+        "keywords": [
+            "framework"
+        ]
+    },
+    {
+        "name": "phpixie/db",
+        "version": "dev-master",
+        "version_normalized": "9999999-dev",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/dracony/PHPixie-DB.git",
+            "reference": "8d6fd658171ec046375b409167941462850ff8f4"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/dracony/PHPixie-DB/zipball/8d6fd658171ec046375b409167941462850ff8f4",
+            "reference": "8d6fd658171ec046375b409167941462850ff8f4",
+            "shasum": ""
+        },
+        "require": {
+            "phpixie/core": "2.*@dev"
+        },
+        "time": "2013-05-11 19:35:58",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "2.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "PHPixie": "classes/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "BSD"
+        ],
+        "authors": [
+            {
+                "name": "Roman Tsiupa",
+                "email": "[email protected]",
+                "homepage": "http://dracony.org"
+            }
+        ],
+        "description": "PHPixie Database library",
+        "homepage": "http://phpixie.com",
+        "keywords": [
+            "database",
+            "mysql",
+            "postgresql",
+            "sqlite"
+        ]
+    },
+    {
+        "name": "phpixie/orm",
+        "version": "dev-master",
+        "version_normalized": "9999999-dev",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/dracony/PHPixie-ORM.git",
+            "reference": "b081caf676e2af832c6856c44ec4695a10064d83"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/dracony/PHPixie-ORM/zipball/b081caf676e2af832c6856c44ec4695a10064d83",
+            "reference": "b081caf676e2af832c6856c44ec4695a10064d83",
+            "shasum": ""
+        },
+        "require": {
+            "phpixie/db": "2.*@dev"
+        },
+        "time": "2013-06-04 14:52:37",
+        "type": "library",
+        "extra": {
+            "branch-alias": {
+                "dev-master": "2.x-dev"
+            }
+        },
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "PHPixie": "classes/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "BSD"
+        ],
+        "authors": [
+            {
+                "name": "Roman Tsiupa",
+                "email": "[email protected]",
+                "homepage": "http://dracony.org"
+            }
+        ],
+        "description": "ORM library for PHPixie",
+        "homepage": "http://phpixie.com",
+        "keywords": [
+            "database",
+            "orm"
+        ]
+    }
+]

+ 4 - 0
php-phpixie/vendor/phpixie/core/README.md

@@ -0,0 +1,4 @@
+PHPixie-Core
+============
+
+PHPixie framework core

+ 126 - 0
php-phpixie/vendor/phpixie/core/assets/views/debug.php

@@ -0,0 +1,126 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<title>Error</title>
+		<style>
+			html{
+				width:100%;
+				min-height:100%;
+				font-family:'Verdana';
+				font-size:14px;
+			}
+			body{
+
+				min-height:100%;
+				background: #a90329; /* Old browsers */
+				background: -moz-radial-gradient(center, ellipse cover, #a90329 0%, #6d0019 100%); /* FF3.6+ */
+				background: -webkit-radial-gradient(center, ellipse cover, #a90329 0%,#6d0019 100%); /* Chrome10+,Safari5.1+ */
+			}
+			#content{
+				width:1000px;
+				margin:auto;
+				padding:10px 0px;
+				background:#eee;
+			}
+			.file{
+				font-weight:bold;
+			}
+			.block{
+				border-bottom:1px solid #000;
+				margin:10px;
+			}
+			.code{
+				
+				padding:10px;
+			}
+			.highlight{
+				background:#efecd0;
+			}
+			#exception{
+				font-size:25px;
+				font-weight:bold;
+				padding:10px;
+			}
+			#debug{
+				border-bottom: 1px solid black;
+				margin: 10px;
+			}
+			#log{
+				font-size:15px;
+				font-weight:bold;
+				padding:5px;
+			}
+			.log{
+				padding:10px;
+				border-bottom: 1px solid black;
+			}
+			.log.odd{
+				
+			}
+			pre{
+				margin:0px;
+			}
+			.thick{
+				border-width:2px;
+			}
+		</style>
+	</head>
+	<body>
+		<?php 
+			$rawblocks=array_merge(array(array(
+				'file'=>$exception->getFile(),
+				'line'=>$exception->getLine()
+			)), $exception->getTrace());
+			$blocks = array();
+			foreach($rawblocks as $block){
+				if(!isset($block['file']))
+					continue;
+				//avoid duplicates
+				if(count($blocks)>0){
+					$last=$blocks[count($blocks)-1];
+					if($block['file']==$last['file'] && $block['line']==$last['line'])
+						continue;
+				}
+				$blocks[]=$block;
+			}
+			
+			
+		?>
+		<div id="content">
+			<div id="exception"><?php echo str_replace("\n",'<br/>',$exception->getMessage()); ?></div>
+			<div id="blocks">
+				<?php foreach($blocks as $bkey=>$block):	?>
+					<div class="block <?php echo (!empty($log)&&$bkey==0)?'thick':''; ?>">
+						<div class="file"><?php echo $block['file'];?></div>
+						<div class="code">
+							<?php 
+								$line=$block['line']-1;
+								$code = explode("\n", file_get_contents($block['file']));
+								$start = $line - 3;
+								if ($start < 0) $start = 0;
+								$end = $line + 3;
+								if($end>=count($code)) $end=count($code)-1;
+								$code=array_slice($code,$start,$end-$start,true);
+							?>
+							
+							<?php foreach($code as $n=>$text):?>
+							<pre class="line <?php echo $n==$line?'highlight':''; ?>"><?php echo ($n+1).'    '.htmlspecialchars($text); ?></pre>
+							<?php endforeach;?>
+						</div>
+					</div>
+					<?php if($bkey==0&&!empty($log)):?>
+						<div id="debug">
+							<div id="log">Logged values:</div>
+							<?php foreach($log as $key=>$val):?>
+								<div class="log <?php echo $key%2?'odd':''; ?>">
+									<pre><?php var_export($val);?></pre>
+								</div>
+							<?php endforeach;?>
+						</div>
+						<div id="log">Call stack:</div>
+					<?php endif;?>
+				<?php endforeach;?>
+			</div>
+		</div>
+	</body>
+</html>

+ 166 - 0
php-phpixie/vendor/phpixie/core/classes/PHPixie/Config.php

@@ -0,0 +1,166 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * Handles retrieving of the configuration options.
+ * You can add configuration files to /assets/config folder
+ * and later access them via the get() method.
+ * @package Core
+ */
+class Config
+{
+
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	protected $pixie;
+	
+	/**
+	 * Array of configuration files and values loaded from them
+	 * @var array
+	 */
+	protected $groups = array();
+
+	/**
+	 * Constructs a config handler
+	 *
+	 * @param \PHPixie\Pixie $pixie Pixie dependency container
+	 */
+	public function __construct($pixie) {
+		$this->pixie = $pixie;
+	}
+	
+	/**
+	 * Loads a group configuration file it has not been loaded before and
+	 * returns its options. If the group doesn't exist creates an empty one
+	 *
+	 * @param string    $name Name of the configuration group to load
+	 * @return array    Array of options for this group
+	 */
+	public function get_group($name)
+	{
+
+		if (!isset($this->groups[$name]))
+		{
+			$file = $this->pixie->find_file('config', $name);
+			$this->load_group($name, $file);
+		}
+
+		return $this->groups[$name]['options'];
+	}
+
+	/**
+	 * Loads group from file
+	 *
+	 * @param string $name Name to assign the loaded group
+	 * @param string $file File to load
+	 */
+	public function load_group($name, $file)
+	{
+		
+		if(!empty($file)){
+			$options = include($file);
+			if (!is_array($options))
+				$options = array();
+		}else {
+			$options = array();
+			$file = $this->pixie-> root_dir.'assets/config/'.$name.'.php';
+		}
+		
+		$this->groups[$name] = array(
+			'file' => $file,
+			'options' => $options
+		);
+	}
+
+	/**
+	 * Retrieves a configuration value. You can use a dot notation
+	 * to access properties in group arrays. The first part of the key
+	 * specifies the configuration file from which options should be loaded from
+	 * <code>
+	 *     //Loads ['default']['user'] option
+	 *     //from database.php configuration file
+	 *     $this->pixie->config->get('database.default.user');
+	 * </code>
+	 *
+	 * @param string    $key Configuration key to retrieve.
+	 * @param string    $default Default value to return if the key is not found.
+	 * @return mixed    Configuration value
+	 * @throws \Exception If default value is not specified and the key is not found
+	 */
+	public function get()
+	{
+		$p = func_get_args();
+
+		$keys = explode('.', $p[0]);
+		$group_name = array_shift($keys);
+		$group = $this->get_group($group_name);
+		if (empty($keys))
+			return $group;
+
+		$total = count($keys);
+		foreach ($keys as $i => $key)
+		{
+			if (isset($group[$key]))
+			{
+				if ($i == $total - 1)
+					return $group[$key];
+				$group = &$group[$key];
+			}else
+			{
+				if (array_key_exists(1, $p))
+					return $p[1];
+				throw new \Exception("Configuration not set for {$p[0]}.");
+			}
+		}
+	}
+
+	/**
+	 * Sets a configuration option.
+	 *
+	 * @param string    $key    Configuration key to set
+	 * @param string    $value  Value to set for this option
+	 */
+	public function set($key, $value)
+	{
+		$keys = explode('.', $key);
+		$group_name = array_shift($keys);
+		$group = $this->get_group($group_name);
+		$subgroup = &$group;
+		$last_key = count($keys) - 1;
+		foreach ($keys as $i => $key)
+		{
+
+			if ($i == $last_key)
+			{
+
+				$subgroup[$key] = $value;
+			}
+			else
+			{
+
+				if (!isset($subgroup[$key]) || !is_array($subgroup[$key])) 
+					$subgroup[$key] = array();
+				
+				$subgroup = & $subgroup[$key];
+			}
+		}
+
+		$this->groups[$group_name]['options'] = $group;
+	}
+
+	/**
+	 * Writes a configuration group back to the file it was loaded from
+	 *
+	 * @param string    $group    Name of the group to write
+	 */
+	public function write($group)
+	{
+		$this->get_group($group);
+		$group = $this->groups[$group];
+		file_put_contents($group['file'], "<?php\r\nreturn ".var_export($group['options'], true).";");
+	}
+
+}

+ 109 - 0
php-phpixie/vendor/phpixie/core/classes/PHPixie/Controller.php

@@ -0,0 +1,109 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * Base Controller class. Controllers contain the  logic of your website,
+ * each action representing a reply to a particular request, e.g. a single page.
+ * @package Core
+ */
+class Controller
+{
+	
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	protected $pixie;
+	
+	/**
+	 * Request for this controller. Holds all input data.
+	 * @var \PHPixie\Request
+	 */
+	public $request;
+
+	/**
+	 * Response for this controller. It will be updated with headers and
+	 * response body during controller execution
+	 * @var \PHPixie\Response
+	 */
+	public $response;
+
+	/**
+	 * If set to False stops controller execution
+	 * @var boolean
+	 */
+	public $execute = true;
+
+	/**
+	 * This method is called before the action.
+	 * You can override it if you need to,
+	 * it doesn't do anything by default.
+	 *
+	 * @return void
+	 */
+	public function before()
+	{
+
+	}
+
+	/**
+	 * This method is called after the action.
+	 * You can override it if you need to,
+	 * it doesn't do anything by default.
+	 *
+	 * @return void
+	 */
+	public function after()
+	{
+
+	}
+
+	/**
+	 * Creates new Controller
+	 *
+	 */
+	public function __construct($pixie)
+	{
+		$this->pixie = $pixie;
+		$this->response = new Response;
+	}
+
+	/**
+	 * Shortcut for redirecting the user.
+	 * Use like this:
+	 * <code>
+	 *     return $this->redirect($url);
+	 * </code>
+	 *
+	 * @param string $url URL to redirect to.
+	 * @return void
+	 */
+	public function redirect($url) {
+		$this->response-> redirect($url);
+		$this->execute = false;
+	}
+	
+	/**
+	 * Runs the appropriate action.
+	 * It will execute the before() method before the action
+	 * and after() method after the action finishes.
+	 *
+	 * @param string    $action Name of the action to execute.
+	 * @return void
+	 * @throws \Exception If the specified action doesn't exist
+	 */
+	public function run($action)
+	{
+		$action = 'action_'.$action;
+		if (!method_exists($this, $action))
+			throw new \Exception("Method {$action} doesn't exist in ".get_class($this), 404);
+		$this->execute = true;
+		$this->before();
+		if ($this->execute)
+			$this->$action();
+		if ($this->execute)
+			$this->after();
+	}
+
+}

+ 154 - 0
php-phpixie/vendor/phpixie/core/classes/PHPixie/Debug.php

@@ -0,0 +1,154 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * Handles error reporting and debugging.
+ * @package Core
+ */
+class Debug
+{
+
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	protected $pixie;
+	
+	/**
+	 * An array of logged items
+	 * @var array
+	 */
+	public $logged = array();
+	
+	/**
+	 * Flag that determines if the errors are displayed
+	 * @var boolean
+	 */
+	public $display_errors = true;
+	
+	/**
+	 * Constructs a debugger
+	 *
+	 * @param \PHPixie\Pixie $pixie Pixie dependency container
+	 */
+	public function __construct($pixie) {
+		$this->pixie = $pixie;
+	}
+	
+	/**
+	 * Displays the error page. If you have 'silent_errors' enabled in
+	 * core.php config file, a small message will be shown instead.
+	 *
+	 * @param \Exception $exception Exception to display
+	 * @return void
+	 */
+	public function render_error($exception)
+	{
+		if (ob_get_length() > 0)
+		{
+			ob_end_clean();
+		}
+
+		if ($exception->getCode() == 404)
+		{
+			$status = '404 Not Found';
+		}
+		else
+		{
+			$status = '503 Service Temporarily Unavailable';
+		}
+
+		header($_SERVER["SERVER_PROTOCOL"].' '.$status);
+		header("Status: {$status}");
+
+		if (!$this->display_errors)
+		{
+			echo $status;
+			return;
+		}
+
+		$view = $this->pixie->view('debug');
+		$view->exception = $exception;
+		$view->log = $this->logged;
+		echo $view->render();
+	}
+
+	/**
+	 * Catches errors and exceptions and sends them
+	 * to the configured handler if one is present,
+	 * otherwise render_error() will be called.
+	 *
+	 * @param \Exception $exception Caught exception
+	 * @return void
+	 */
+	public function onError($exception)
+	{
+		set_exception_handler(array($this, 'internalException'));
+		set_error_handler(array($this, 'internalError'), E_ALL);
+		$this->render_error($exception);
+	}
+
+	/**
+	 * Converts PHP Errors to Exceptions
+	 *
+	 * @param string        $errno   Error number
+	 * @param string        $errstr  Error message
+	 * @param string        $errfile File in which the error occurred
+	 * @param string        $errline Line at which the error occurred
+	 * @return void
+	 * @throws \ErrorException Throws converted exception to be immediately caught
+	 */
+	public function errorHandler($errno, $errstr, $errfile, $errline)
+	{
+		throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);
+	}
+
+	/**
+	 * Handles exceptions that occurred while inside the error handler. Prevents recursion.
+	 *
+	 * @param \Exception  $exception Caught exception
+	 * @return void
+	 */
+	public function internalException($exception)
+	{
+		echo $exception->getMessage().' in '.$exception->getFile().' on line '.$exception->getLine();
+	}
+
+	/**
+	 * Handles errors that occurred while inside the error handler. Prevents recursion.
+	 *
+	 * @param string        $errno   Error number
+	 * @param string        $errstr  Error message
+	 * @param string        $errfile File in which the error occurred
+	 * @param string        $errline Line at which the error occurred
+	 * @return void
+	 */
+	public function internalError($errno, $errstr, $errfile, $errline)
+	{
+		echo $errstr.' in '.$errfile.' on line '.$errline;
+	}
+
+	/**
+	 * Initializes the error handler
+	 *
+	 * @return void
+	 */
+	public function init()
+	{
+		set_exception_handler(array($this, 'onError'));
+		set_error_handler(array($this, 'errorHandler'), E_ALL);
+	}
+
+	/**
+	 * Adds an item to the log.
+	 *
+	 * @param mixed $val Item to be logged
+	 * @return void
+	 */
+	public function log($val)
+	{
+		array_unshift($this->logged, $val);
+	}
+
+}

+ 250 - 0
php-phpixie/vendor/phpixie/core/classes/PHPixie/Pixie.php

@@ -0,0 +1,250 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * The core of the framework and it's dependancy container.
+ * It holds references to all framework wide instances, like Config,
+ * Session, Debug etc. Instead of calling a class constructor you call 
+ * a wrapping function of this class to construct the object for you.
+ * You can extend this class adding porperties that you want to be accessible
+ * all around your app.
+ *
+ * @property-read \PHPixie\Config $config Configuration handler
+ * @property-read \PHPixie\Debug $debug Error handler and logger
+ * @property-read \PHPixie\Router $router Router
+ * @property-read \PHPixie\Session $config Session handler
+ */
+
+ class Pixie {
+	
+  	/**
+	 * Instance definitions
+	 * @var array
+	 */
+	protected $instance_classes = array(
+		'config'  => '\PHPixie\Config',
+		'debug'   => '\PHPixie\Debug',
+		'router'  => '\PHPixie\Router',
+		'session' => '\PHPixie\Session',
+	);
+	
+ 	/**
+	 * Instanced classes
+	 * @var array
+	 */
+	protected $instances = array();
+	
+	/**
+	 * Module definitions
+	 * @var array
+	 */
+	protected $modules = array();
+	
+ 	/**
+	 * Directories to look for assets in
+	 * @var array
+	 */
+	public $assets_dirs = array();
+	
+ 	/**
+	 * Root directory of the application
+	 * @var array
+	 */
+	public $root_dir;
+	
+	/**
+	 * Namespace of the application
+	 * @var array
+	 */
+	public $app_namespace;
+	
+	/**
+	 * Base URL of the application
+	 * @var string
+	 */
+	public $basepath = '/';
+	
+	/**
+	 * Gets a property by name. Returns defined class and module instances
+	 *
+	 * @param string $name Property namw
+	 * @return mixed Instance of defined class or module
+	 */
+	public function __get($name) {
+		if (isset($this->instances[$name]))
+			return $this->instances[$name];
+			
+		if (isset($this->instance_classes[$name]))
+			return $this->instances[$name] = new $this->instance_classes[$name]($this);
+			
+		if (isset($this->modules[$name]))
+			return $this->instances[$name] = new $this->modules[$name]($this);
+			
+		throw new \Exception("Property {$name} not found on ".get_class($this));
+	}		
+
+	/**
+	 * Constructs a controller by class name
+	 *
+	 * @param string $class Controller class
+	 * @return \PHPixie\Controller
+	 */
+	public function controller($class) {
+		if (!class_exists($class))
+			throw new \Exception("Class {$class} doesn't exist", 404);
+		return new $class($this);
+	}
+	
+	/**
+	 * Constructs a request
+	 *
+	 * @param  Route  $route  Route for this request
+	 * @param  string $method HTTP method for the request (e.g. GET, POST)
+	 * @param  array  $post   Array of POST data
+	 * @param  array  $get    Array of GET data
+	 * @param  array  $server Array of SERVER data
+	 * @return \PHPixie\Request
+	 */
+	public function request($route, $method = "GET", $post = array(), $get = array(), $param=array(), $server = array()) {
+		return new \PHPixie\Request($this, $route, $method, $post, $get, $param, $server);
+	}
+	
+	/**
+	 * Constructs a response
+	 *
+	 * @return \PHPixie\Response
+	 */
+	public function response() {
+		return new \PHPixie\Response;
+	}
+	
+	/**
+	 * Constructs a route
+	 *
+	 * @param string $name Name of the route
+	 * @param mixed $rule Rule for this route
+	 * @param array $defaults Default parameters for the route
+	 * @param mixed $methods Methods to restrict this route to.
+	 *                       Either a single method or an array of them.
+	 * @return \PHPixie\Route
+	 */
+	public function route($name, $rule, $defaults, $methods = null) {
+		return new \PHPixie\Route($name, $rule, $defaults, $methods);
+	}
+	
+	/**
+	 * Constructs a view
+	 *
+	 * @param string   $name The name of the template to use
+	 * @return \PHPixie\View
+	 */
+	public function view($name)
+	{
+		return new \PHPixie\View($this, $name);
+	}
+	
+	/**
+	 * Retrieve value from array by key, with default value support.
+	 *
+	 * @param array  $array   Input array
+	 * @param string $key     Key to retrieve from the array
+	 * @param mixed  $default Default value to return if the key is not found
+	 * @return mixed An array value if it was found or default value if it is not
+	 */
+	public function arr($array, $key, $default = null)
+	{
+		if (isset($array[$key]))
+			return $array[$key];
+		return $default;
+	}
+	
+	/**
+	 * Finds full path to a specified file in the /assets folders.
+	 * It will search in the application folder first, then in all enabled modules
+	 * and then the /assets folder of the framework.
+	 *
+	 * @param string  $subfolder  Subfolder to search in e.g. 'classes' or 'views'
+	 * @param string  $name       Name of the file without extension
+	 * @param string  $extension  File extension
+	 * @param boolean $return_all If 'true' returns all mathced files as array,
+	 *                            otherwise returns the first file found
+	 * @return mixed  Full path to the file or False if it is not found
+	 * @static
+	 */
+	public function find_file($subfolder, $name, $extension = 'php', $return_all = false)
+	{
+		
+		$fname = $name.'.'.$extension;
+		$found_files = array();
+		foreach ($this->assets_dirs as $folder)
+		{
+			$file = $folder.$subfolder.'/'.$fname;
+			if (file_exists($file))
+			{
+				if (!$return_all)
+					return($file);
+					
+				$found_files[] = $file;
+			}
+		}
+		
+		if (!empty($found_files))
+			return $found_files;
+
+		return false;
+	}
+	
+	/**
+	 * Creates a Request representing current HTTP request.
+	 *
+	 * @return \PHPixie\Request
+	 */
+	public function http_request()
+	{
+		$uri = $_SERVER['REQUEST_URI'];
+		$uri = preg_replace("#^{$this->basepath}(?:index\.php/)?#i", '/', $uri);
+		$url_parts = parse_url($uri);
+		$route_data = $this->router->match($url_parts['path'], $_SERVER['REQUEST_METHOD']);
+		return $this->request($route_data['route'], $_SERVER['REQUEST_METHOD'], $_POST, $_GET, $route_data['params'], $_SERVER);
+	}
+	
+	/**
+	 * Bootstraps the project
+	 *
+	 * @param  string $root_dir Root directory of the application
+	 * @return void
+	 */
+	public function bootstrap($root_dir) {
+		if (substr($root_dir, -1) != '/')
+			$root_dir.= '/';
+			
+		$this->root_dir = $root_dir;
+		
+		if ($this->app_namespace === null) {
+			$class_name = get_class($this);
+			$this->app_namespace = substr($class_name, 0, strpos($class_name, "\\")+1);
+		}
+		$this->assets_dirs[] = dirname(dirname(dirname(__FILE__))).'/assets/';
+		$this->debug->init();
+		foreach($this->modules as $name=>$class) {
+			$this->$name = new $class($this);
+		}
+		array_unshift($this->assets_dirs, $this->root_dir.'assets/');
+		foreach($this->config->get('routes') as $name => $rule) 
+			$this->router->add($this->route($name, $rule[0], $rule[1], $this->arr($rule, 2, null)));
+			
+		$this->after_bootstrap();
+		
+		return $this;
+	}
+	
+	/**
+	 * Perform some initialization after bootstrap finished
+	 *
+	 * @return void
+	 */
+	protected function after_bootstrap() {}
+	
+		
+}

+ 200 - 0
php-phpixie/vendor/phpixie/core/classes/PHPixie/Request.php

@@ -0,0 +1,200 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * Handles client request.
+ * @package Core
+ */
+class Request
+{
+
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	protected $pixie;
+	
+	/**
+	 * Stores POST data
+	 * @var array
+	 */
+	protected $_post;
+
+	/**
+	 * Stores GET data
+	 * @var array
+	 */
+	protected $_get;
+
+	/**
+	 * Stores GET data
+	 * @var array
+	 */
+	protected $_param;
+	
+	/**
+	 * Current Route
+	 * @var Route
+	 */
+	public $route;
+
+	/**
+	 * Request method
+	 * @var string
+	 */
+	public $method;
+
+	/**
+	 * Creates a new request
+	 *
+	 * @param \PHPixie\Pixie $pixie Pixie dependency container
+	 * @param \PHPixie\Route  $route  Route for this request
+	 * @param  string $method HTTP method for the request (e.g. GET, POST)
+	 * @param  array  $post   Array of POST data
+	 * @param  array  $get    Array of GET data
+	 * @param  array  $server Array of SERVER data
+	 * @return Request Initialized request
+	 *
+	 */
+	public function __construct($pixie, $route, $method = "GET", $post = array(), $get = array(), $param=array(), $server = array())
+	{
+		$this->pixie = $pixie;
+		$this->route = $route;
+		$this->method = $method;
+		$this->_post = $post;
+		$this->_get = $get;
+		$this->_param = $param;
+		$this->_server = $server;
+	}
+
+	/**
+	 * Retrieves a GET parameter
+	 *
+	 * @param string $key    Parameter key
+	 * @param mixed $default Default value
+	 * @param bool  $filter_xss Whether to filter input for XSS protection
+	 * @return mixed Returns a value if a key is specified,
+	 *               or an array of GET parameters if it isn't.
+	 */
+	public function get($key = null, $default = null, $filter_xss=true)
+	{
+		if ($key == null)
+			return $this->_get;
+		$val = $this->pixie->arr($this->_get, $key, $default);
+		
+		if ($filter_xss)
+			return $this->filter_xss($val);
+			
+		return $val;
+	}
+
+	/**
+	 * Retrieves a POST parameter
+	 *
+	 * @param string $key    Parameter key
+	 * @param mixed $default Default value
+	 * @param bool  $filter_xss Whether to filter input for XSS protection
+	 * @return mixed Returns a value if a key is specified,
+	 *               or an array of POST parameters if it isn't.
+	 */
+	public function post($key = null, $default = null, $filter_xss=true)
+	{
+		if ($key == null)
+			return $this->_post;
+		$val = $this->pixie->arr($this->_post, $key, $default);
+		
+		if ($filter_xss)
+			return $this->filter_xss($val);
+			
+		return $val;
+	}
+
+	/**
+	 * Filters input to prevent XSS attacks.
+	 * If an array is passed, filters all its elements recursively.
+	 *
+	 * @param mixed $val  Input to sanitize.
+	 * @return mixed Filtered values
+	 */
+	public function filter_xss($val) {
+		if (is_array($val)) {
+			array_walk_recursive($val, function( &$str) {
+				$str = strip_tags($str);
+			});
+		}else {
+			$val = strip_tags($val);
+		}
+		
+		return $val;
+	}
+	
+	/**
+	 * Retrieves a SERVER parameter
+	 *
+	 * @param string $key    Parameter key
+	 * @param mixed  $default Default value
+	 * @return mixed Returns a value if a key is specified,
+	 *               or an array of SERVER parameters if it isn't.
+	 */
+	public function server($key = null, $default = null)
+	{
+		if ($key == null)
+			return $this->_server;
+		return $this->pixie->arr($this->_server, $key, $default);
+	}
+
+	/**
+	 * Retrieves a URL parameter
+	 *
+	 * @param string $key    Parameter key
+	 * @param mixed $default Default value
+	 * @param bool  $filter_xss Whether to filter input for XSS protection
+	 * @return mixed Returns a value if a key is specified,
+	 *               or an array of POST parameters if it isn't.
+	 */
+	public function param($key = null, $default = null, $filter_xss=true)
+	{
+		if ($key == null)
+			return $this->_param;
+		$val = $this->pixie->arr($this->_param, $key, $default);
+		
+		if ($filter_xss)
+			return $this->filter_xss($val);
+			
+		return $val;
+	}
+
+	/**
+	 * Initializes the routed Controller and executes specified action
+	 *
+	 * @return \PHPixie\Response A Response object with the body and headers set
+	 */
+	public function execute()
+	{
+		$class = $this->param('namespace',$this->pixie->app_namespace).'Controller\\'.ucfirst($this->param('controller'));
+		$controller = $this->pixie->controller($class);
+		$controller->request = $this;
+		$controller->run($this->param('action'));
+		return $controller->response;
+	}
+
+	/**
+	 * Gets request URL
+	 *
+	 * @param bool $with_params Whether to preserve URL parameters
+	 * @return string URL of this request
+	 */
+	public function url($with_params = false) {
+		$url = $this->server('HTTPS') == 'on' ? 'https://':'http://';
+		$url.= $this->server('HTTP_HOST').$this->server('REQUEST_URI');
+
+		if (!$with_params) {
+			$pos = strpos($url, '?');
+			if ($pos !== false)
+				$url = substr($url, 0, $pos);
+		}
+		return $url;
+	}
+	
+}

+ 71 - 0
php-phpixie/vendor/phpixie/core/classes/PHPixie/Response.php

@@ -0,0 +1,71 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * Handles the response that is sent back to the client.
+ * @package Core
+ */
+class Response
+{
+
+	/**
+	 * Headers for the response
+	 * @var array
+	 */
+	public $headers = array(
+		'Content-Type: text/html; charset=utf-8'
+	);
+
+	/**
+	 * Response body
+	 * @var string
+	 */
+	public $body;
+
+	/**
+	 * Add header to the response
+	 *
+	 * @param string $header Header content
+	 * @return void
+	 */
+	public function add_header($header)
+	{
+		$this->headers[] = $header;
+	}
+
+	/**
+	 * Add redirection header
+	 *
+	 * @param string $url URL to redirect the client to
+	 * @return void
+	 */
+	public function redirect($url)
+	{
+		$this->add_header("Location: $url");
+	}
+
+	/**
+	 * Sends headers to the client
+	 *
+	 * @return \PHPixie\Response Resturns itself
+	 */
+	public function send_headers()
+	{
+		foreach ($this->headers as $header)
+			header($header);
+		return $this;
+	}
+
+	/**
+	 * Send response body to the client
+	 *
+	 * @return \PHPixie\Response Resturns itself
+	 */
+	public function send_body()
+	{
+		echo $this->body;
+		return $this;
+	}
+
+}

+ 98 - 0
php-phpixie/vendor/phpixie/core/classes/PHPixie/Route.php

@@ -0,0 +1,98 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * Routing class to extract and parse request parameters from the URL.
+ * @package Core
+ */
+class Route
+{
+
+	/**
+	 * Name of the route.
+	 * @var string
+	 */
+	public $name;
+
+	/**
+	 * Rule for this route.
+	 * @var mixed
+	 */
+	public $rule;
+
+	/**
+	 * Default parameters for this route.
+	 * @var mixed
+	 */
+	public $defaults;
+
+	/**
+	 * Methods to restrict this route to.
+	 * @var array
+	 */
+	public $methods;
+
+	/**
+	 * Associative array of route instances.
+	 * @var array
+	 */
+	private static $routes = array();
+
+	/**
+	 * Constructs a route.
+	 *
+	 * @param string $name Name of the route
+	 * @param mixed $rule Rule for this route
+	 * @param array $defaults Default parameters for the route
+	 * @param mixed $methods Methods to restrict this route to.
+	 *                       Either a single method or an array of them.
+	 */
+	public function __construct($name, $rule, $defaults, $methods = null)
+	{
+		$this->name = $name;
+		$this->rule = $rule;
+		$this->defaults = $defaults;
+		if($methods != null){
+			if (is_string($methods))
+				$methods = array($methods);
+			$methods = array_map('strtoupper', $methods);
+		}
+		$this->methods = $methods;
+	}
+
+	/**
+	 * Generates a url for a route
+	 *
+	 * @param array $params    Parameters to substitute in the route
+	 * @param bool $absolute   Whether to return an absolute url
+	 * @param string $protocol	Protocol to use for absolute url
+	 * @return string Generated url
+	 */
+	public function url($params = array(), $absolute = false, $protocol = 'http')
+	{
+		if (is_callable($this->rule))
+			throw new \Exception("The rule for '{$this->name}' route is a function and cannot be reversed");
+
+		$url = is_array($this->rule) ? $this->rule[0] : $this->rule;
+
+		$replace = array();
+		$params = array_merge($this->defaults, $params);
+		foreach ($params as $key => $value)
+			$replace["<{$key}>"] = $value;
+		$url = str_replace(array_keys($replace), array_values($replace), $url);
+
+		$count = 1;
+		$chars = '[^\(\)]*?';
+		while ($count > 0)
+			$url = preg_replace("#\({$chars}<{$chars}>{$chars}\)#", '', $url, -1, $count);
+
+		$url = str_replace(array('(', ')'), '', $url);
+
+		if ($absolute)
+			$url = $protocol.'://'.$_SERVER['HTTP_HOST'].$url;
+
+		return $url;
+	}
+
+}

+ 130 - 0
php-phpixie/vendor/phpixie/core/classes/PHPixie/Router.php

@@ -0,0 +1,130 @@
+<?php
+namespace PHPixie;
+
+/**
+ * Router for matching URLs to corresponding Routes
+ * @package Core
+ */
+class Router {
+
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	protected $pixie;
+	
+	/**
+	 * Associative array of route instances.
+	 * @var array
+	 */
+	protected $routes = array();
+	
+	/**
+	 * Constructs a router
+	 *
+	 * @param \PHPixie\Pixie $pixie Pixie dependency container
+	 */
+	public function __construct($pixie) {
+		$this->pixie = $pixie;
+	}
+
+	
+	/**
+	 * Ads a route
+	 *
+	 * @param string $name     Name of the route. Routes with the same name will override one another.
+	 * @param mixed $rule     Either an expression to match URI against or a function that will
+	 *                        be passed the URI and must return either an associative array of
+	 *                        extracted parameters (if it matches) or False.
+	 * @param array   $defaults An associated array of default values.
+	 * @return void
+	 */
+	public function add($route)
+	{
+		$this->routes[$route->name] = $route;
+	}
+
+	/**
+	 * Gets route by name
+	 *
+	 * @param string $name Route name
+	 * @return \PHPixie\Route
+	 * @throws \Exception If specified route doesn't exist
+	 */
+	public function get($name)
+	{
+		if (!isset($this->routes[$name]))
+			throw new \Exception("Route {$name} not found.");
+
+		return $this->routes[$name];
+	}
+
+	/**
+	 * Matches the URI against available routes to find the correct one.
+	 *
+	 * @param string   $uri Request URI
+	 * @param string   $method Request method
+	 * @return array Array containing route and matched parameters
+	 * @throws \Exception If no route matches the URI
+	 * @throws \Exception If route matched but no Controller was defined for it
+	 * @throws \Exception If route matched but no action was defined for it
+	 */
+	public function match($uri, $method = 'GET')
+	{
+		$matched = false;
+		$method = strtoupper($method);
+		foreach ($this->routes as $name => $route) {
+			if ($route-> methods != null && !in_array($method, $route->methods))
+				continue;
+			
+			$rule = $route->rule;
+			if (is_callable($rule))
+			{
+				if (($data = $rule($uri)) !== FALSE)
+				{
+					$matched = $name;
+					break;
+				}
+			}
+			else
+			{
+				$pattern = is_array($rule) ? $rule[0] : $rule;
+				$pattern = str_replace(')', ')?', $pattern);
+				$pixie=$this->pixie;
+				$pattern = preg_replace_callback('/<.*?>/', function($str) use ($rule, $pixie) {
+						$str = $str[0];
+						$regexp = '[a-zA-Z0-9\-\._]+';
+						if (is_array($rule))
+							$regexp = $pixie->arr($rule[1], str_replace(array('<', '>'), '', $str), $regexp);
+						return '(?P'.$str.$regexp.')';
+					}, $pattern);
+
+				preg_match('#^'.$pattern.'/?$#', $uri, $match);
+				if (!empty($match[0]))
+				{
+					$matched = $name;
+					$data = array();
+					foreach ($match as $k => $v)
+						if (!is_numeric($k))
+							$data[$k] = $v;
+					break;
+				}
+			}
+		}
+		if ($matched == false)
+			throw new \Exception('No route matched your request', 404);
+			
+		$route = $this->routes[$matched];
+		$params = array_merge($route->defaults, $data);
+		if (!isset($params['controller']))
+			throw new \Exception("Route {$matched} matched, but no controller was defined for this route", 404);
+		if (!isset($params['action']))
+			throw new \Exception("Route {$matched} matched with controller {$params['controller']}, but no action was defined for this route", 404);
+
+		return array(
+					'route'=>$route, 
+					'params'=>$params
+					);
+	}
+	
+}

+ 119 - 0
php-phpixie/vendor/phpixie/core/classes/PHPixie/Session.php

@@ -0,0 +1,119 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * Simple class for accessing session data
+ * @package Core
+ */
+class Session
+{
+
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	protected $pixie;
+	
+	/**
+	 * Constructs session handler
+	 *
+	 * @param \PHPixie\Pixie $pixie Pixie dependency container
+	 */
+	public function __construct($pixie) {
+		$this->pixie=$pixie;
+	}
+	/**
+	 * Makes sure the session is initialized
+	 *
+	 * @return void
+	 */
+	private function check()
+	{
+		if (!session_id())
+		{
+			session_start();
+		}
+	}
+
+	/**
+	 * Gets a session variable
+	 *
+	 * @param string $key     Variable name
+	 * @param mixed $default Default value
+	 * @return mixed Session value
+	 */
+	public function get($key, $default = null)
+	{
+		$this->check();
+		return $this->pixie->arr($_SESSION, $key, $default);
+	}
+
+	/**
+	 * Sets a session variable
+	 *
+	 * @param string $key Variable name
+	 * @param mixed $val Variable value
+	 * @return void
+	 */
+	public function set($key, $val)
+	{
+		$this->check();
+		$_SESSION[$key] = $val;
+	}
+
+	/**
+	 * Removes a session variable
+	 *
+	 * @param string $key Variable name
+	 * @return void
+	 */
+	public function remove($key)
+	{
+		$this->check();
+
+		if (!isset($_SESSION[$key]))
+			return;
+
+		$var = $_SESSION[$key];
+		unset($_SESSION[$key], $var);
+	}
+
+	/**
+	 * Resets the session
+	 *
+	 * @return void
+	 */
+	public function reset()
+	{
+		$this->check();
+		$_SESSION = array();
+	}
+
+	/**
+	 * Gets ot sets flash messages.
+	 * If the value parameter is passed the message is set, otherwise it is retrieved.
+	 * After the message is retrieved for the first time it is removed.
+	 *
+	 * @param $key  The name of the flash message
+	 * @param $val  Flash message content
+	 * @return mixed
+	 */
+	public function flash($key, $val = null)
+	{
+		$this->check();
+		$key = "flash_{$key}";
+		if ($val != null)
+		{
+			$this->set($key, $val);
+		}
+		else
+		{
+			$val = $this->get($key);
+			$this->remove($key);
+		}
+
+		return $val;
+	}
+
+}

+ 106 - 0
php-phpixie/vendor/phpixie/core/classes/PHPixie/View.php

@@ -0,0 +1,106 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * Manages passing variables to templates and rendering them
+ * @package Core
+ */
+class View
+{
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	protected $pixie;
+	
+	/**
+	 * Full path to template file
+	 * @var string
+	 */
+	protected $path;
+
+	/**
+	 * The name of the view.
+	 * @var string
+	 */
+	public $name;
+
+	/**
+	 * Stores all the variables passed to the view
+	 * @var array
+	 */
+	protected $_data = array();
+
+	/**
+	 * File extension of the templates
+	 * @var string
+	 */
+	protected $_extension = 'php';
+
+	/**
+	 * Constructs the view
+	 *
+	 * @param \PHPixie\Pixie $pixie Pixie dependency container
+	 * @param string   $name The name of the template to use
+	 * @throws \Exception If specified template is not found
+	 */
+	public function __construct($pixie, $name)
+	{
+		$this->pixie = $pixie;
+		$this->name = $name;
+		$file = $this->pixie->find_file('views', $name, $this->_extension);
+			
+		if ($file == false)
+			throw new \Exception("View {$name} not found.");
+
+		$this->path = $file;
+	}
+
+	/**
+	 * Manages storing the data passed to the view as properties
+	 *
+	 * @param string $key Property name
+	 * @param string $val Property value
+	 * @return void
+	 */
+	public function __set($key, $val)
+	{
+		$this->_data[$key] = $val;
+	}
+
+	/**
+	 * Manages accessing passed data as properties
+	 *
+	 * @param string   $key Property name
+	 * @return mixed	Property value
+	 * @throws \Exception If the property is not found
+	 */
+	public function __get($key)
+	{
+		if (isset($this->_data[$key]))
+			return $this->_data[$key];
+		throw new \Exception("Value {$key} not set for view {$this->name}");
+	}
+
+	/**
+	 * Renders the template, all dynamically set properties
+	 * will be available inside the view file as variables.
+	 * Example:
+	 * <code>
+	 * $view = $this->pixie->view('frontpage');
+	 * $view->title = "Page title";
+	 * echo $view->render();
+	 * </code>
+	 *
+	 * @return string Rendered template
+	 */
+	public function render()
+	{
+		extract($this->_data);
+		ob_start();
+		include($this->path);
+		return ob_get_clean();
+	}
+	
+}

+ 26 - 0
php-phpixie/vendor/phpixie/core/composer.json

@@ -0,0 +1,26 @@
+{
+    "name": "phpixie/core",
+    "description": "PHPixie Framework",
+    "keywords": ["framework"],
+    "homepage": "http://phpixie.com",
+    "type": "library",
+    "license": "BSD",
+    "authors": [
+        {
+            "name": "Roman Tsiupa",
+            "email": "[email protected]",
+            "homepage": "http://dracony.org"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.0"
+    },
+    "autoload": {
+        "psr-0": {"PHPixie": "classes/"}
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "2.*-dev"
+        }
+    }
+}

+ 10 - 0
php-phpixie/vendor/phpixie/core/tests/bootstrap.php

@@ -0,0 +1,10 @@
+<?php
+if(!defined('INIT')) {	
+	define('ROOT',dirname(dirname(dirname(dirname(dirname(__FILE__))))));
+	$loader = require_once(ROOT.'/vendor/autoload.php');
+	$loader->add('PHPixie', ROOT.'/vendor/phpixie/core/classes/');
+	$loader->add('PHPixie', ROOT.'/vendor/phpixie/db/classes/');
+	$loader->add('PHPixie',ROOT.'/vendor/phpixie/orm/classes/');
+	define('INIT', true);
+}
+	

+ 108 - 0
php-phpixie/vendor/phpixie/core/tests/configTest.php

@@ -0,0 +1,108 @@
+<?php
+
+
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator on 2013-02-06 at 09:17:25.
+ */
+class configTest extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Config
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$this->file = $file = tempnam(sys_get_temp_dir(), 'view');
+		file_put_contents($file, "<?php return ".var_export(array(
+				'trees' => array(
+					'oak' => array(
+						'fairy' => 'Tinkerbell'
+					)
+				)
+				), true).';');
+		$pixie = $this->getMock("\\PHPixie\\Pixie", array('find_file'));
+		$pixie->expects($this->once())
+                 ->method('find_file')
+                 ->will($this->returnValue($this->file));
+		$this->object = new \PHPixie\Config($pixie);
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+		unlink($this->file);
+	}
+
+	/**
+	 * @covers $this->object->get_group
+	 * @todo   Implement testGet_group().
+	 */
+	public function testGet_group()
+	{
+		$group = $this->object->get_group('test');
+		$this->assertArrayHasKey('trees', $group);
+		$this->assertArrayHasKey('oak', $group['trees']);
+		$this->assertArrayHasKey('fairy', $group['trees']['oak']);
+		$this->assertEquals($group['trees']['oak']['fairy'], 'Tinkerbell');
+	}
+
+	/**
+	 * @covers $this->object->get
+	 * @todo   Implement testGet().
+	 */
+	public function testGet()
+	{
+		$this->assertEquals($this->object->get('test.trees.oak.fairy'), 'Tinkerbell');
+		$this->assertEquals($this->object->get('test.trees.oak.fairies', 'default'), 'default');
+	}
+
+	/**
+	 * @covers $this->object->set
+	 * @todo   Implement testSet().
+	 */
+	public function testSet()
+	{
+		$this->object->set('test.trees.oak.second_fairy', 'Trixie');
+		$this->assertEquals($this->object->get('test.trees.oak.second_fairy'), 'Trixie');
+	}
+
+	/**
+	 * @covers $this->object->write
+	 * @todo   Implement testWrite().
+	 */
+	public function testWrite()
+	{
+		$this->object->set('test.trees.oak.second_fairy', 'Trixie');
+		$this->object->write('test');
+		$group = include($this->file);
+		$this->assertArrayHasKey('trees', $group);
+		$this->assertArrayHasKey('oak', $group['trees']);
+		$this->assertArrayHasKey('second_fairy', $group['trees']['oak']);
+		$this->assertEquals($group['trees']['oak']['second_fairy'], 'Trixie');
+	}
+	
+	public function testEmpty()
+	{
+		file_put_contents($this->file, '');
+		$this->assertEquals($this->object->get('test.trees.oak.fairies', 'default'), 'default');
+		$this->object->set('test.trees.oak.second_fairy', 'Trixie');
+		$this->assertEquals($this->object->get('test.trees.oak.second_fairy'), 'Trixie');
+		$this->object->write('test');
+		$group = $this->object->get('test');
+		$this->assertArrayHasKey('trees', $group);
+		$this->assertArrayHasKey('oak', $group['trees']);
+		$this->assertArrayHasKey('second_fairy', $group['trees']['oak']);
+		$this->assertEquals($group['trees']['oak']['second_fairy'], 'Trixie');
+	}
+
+}

+ 58 - 0
php-phpixie/vendor/phpixie/core/tests/controllerTest.php

@@ -0,0 +1,58 @@
+<?php
+require_once(ROOT.'/vendor/phpixie/core/classes/PHPixie/Controller.php');
+class TestController extends \PHPixie\Controller {
+	public $counter = 0;
+	public function before() {
+		$this->counter++;
+	}
+	public function action_index() {
+		$this->counter++;
+	}
+	public function after() {
+		$this->counter++;
+	}
+}
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator on 2013-02-05 at 16:39:57.
+ */
+class ControllerTest extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Controller
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$this->object = new TestController(null);
+	}
+	
+	public function testRedirect() {
+		$this->object->redirect('http://google.com');
+		$this->assertEquals(false,$this->object->execute);
+		$this->assertContains('Location: http://google.com', $this->object->response->headers);
+	}
+	public function testRun()
+	{
+		$this->object->run('index');
+		$this->assertEquals($this->object->counter, 3);
+	}
+
+	public function testException()
+	{
+		$except = false;
+		try {
+			$this->object->run('bogus');
+		} catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals($except, true);
+	}
+
+}

+ 1 - 0
php-phpixie/vendor/phpixie/core/tests/phpunit.xml

@@ -0,0 +1 @@
+<phpunit bootstrap="bootstrap.php"></phpunit>

+ 105 - 0
php-phpixie/vendor/phpixie/core/tests/pixieTest.php

@@ -0,0 +1,105 @@
+<?php
+namespace PixieTest {
+	require_once(ROOT.'/vendor/phpixie/core/classes/PHPixie/Pixie.php');
+	class Pixie extends \PHPixie\Pixie { 
+		public $basepath = '/tester/';
+		protected $modules = array(
+			'mod'=>'\PixieTest\PixieMod'
+		);
+		protected $instance_classes = array(
+		'config'  => '\PixieTest\Config',
+		'debug'   => '\PHPixie\Debug',
+		'router'  => '\PHPixie\Router'
+	);
+	}
+	class PixieMod { }
+	class Config {
+		public function get() {
+			return array();
+		}
+	}
+	class TestController extends \PHPixie\Controller {}
+}
+namespace {
+	/**
+	 * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-04-15 at 21:57:25.
+	 */
+	class PixieTest extends PHPUnit_Framework_TestCase
+	{
+		/**
+		 * @var Pixie
+		 */
+		protected $object;
+
+		/**
+		 * Sets up the fixture, for example, opens a network connection.
+		 * This method is called before a test is executed.
+		 */
+		protected function setUp()
+		{
+			$this->object = new \PixieTest\Pixie();
+			$this->object->bootstrap(sys_get_temp_dir());
+		}
+		
+		public function testBootstrap() {
+			$this->assertEquals("PixieTest\\", $this->object->app_namespace);
+			$this->assertEquals(true, $this->object->mod instanceof \PixieTest\PixieMod );
+			$this->assertEquals(true, $this->object->config instanceof \PixieTest\Config );
+			$this->assertEquals('/', substr($this->object->root_dir,-1));
+		}
+		
+		public function testArr() {
+			$this->assertEquals('a', $this->object->arr(array('c'=>'a'),'c','b'));
+			$this->assertEquals('b', $this->object->arr(array('c'=>'a'),'d','b'));
+		}
+		
+		public function testHttp_Request() {
+			$this->object->router->add(new \PHPixie\Route('default', '/<controller>/<action>', array()));
+			$_SERVER['REQUEST_URI'] = "/tester/home/index";
+			$_POST['post'] = "test";
+			$_GET['get'] = "test";
+			$_SERVER['REQUEST_METHOD'] = "POST";
+			$req = $this->object->http_request();
+			$this->assertEquals($req->get('get'), 'test');
+			$this->assertEquals($req->post('post'), 'test');
+			$this->assertEquals($req->server('REQUEST_METHOD'), 'POST');
+			$this->assertEquals($req->method, 'POST');
+			$this->assertEquals($req->param('controller'), 'home');
+			$this->assertEquals($req->param('action'), 'index');
+		}
+		
+		public function testFind_file() {
+			$dir = $this->object->root_dir.'/assets';
+			if(!is_dir($dir))
+				mkdir($dir);
+			file_put_contents($dir.'/test.php','');
+			$file = $this->object->find_file('','test');
+			$this->assertEquals(true, strpos($file, 'test.php') > 0);
+			unlink($dir.'/test.php');
+			rmdir($dir);
+		}
+		
+		public function testResponse() {
+			$this->assertEquals('PHPixie\Response', get_class($this->object->response()));
+		}
+		
+		public function testRoute() {
+			$route = $this->object->route('a','/',array(),'POST');
+			$this->assertEquals('PHPixie\Route', get_class($route));
+			$this->assertEquals('POST', $route->methods[0]);
+		}
+		public function testRequest() {
+			$this->assertEquals('PHPixie\Request', get_class($this->object->request(null)));
+		}
+		public function testController() {
+			$this->assertEquals('PixieTest\TestController', get_class($this->object->controller('\PixieTest\TestController')));
+		}
+		public function testView() {
+			$mock = $this->getMock('\PixieTest\Pixie', array('find_file'));
+			$mock->expects($this->once())
+                 ->method('find_file')
+                 ->will($this->returnValue('test'));
+			$this->assertEquals('PHPixie\View', get_class($mock->view('test')));
+		}
+	}
+}

+ 158 - 0
php-phpixie/vendor/phpixie/core/tests/requestTest.php

@@ -0,0 +1,158 @@
+<?php
+namespace Controller {
+
+	class TestController extends \PHPixie\Controller {
+		public function action_index(){}
+	}
+}
+
+namespace {
+
+
+
+	/**
+	 * Generated by PHPUnit_SkeletonGenerator on 2013-02-06 at 16:12:22.
+	 */
+	class requestTest extends PHPUnit_Framework_TestCase
+	{
+
+		/**
+		 * @var Request
+		 */
+		protected $object;
+
+		/**
+		 * Sets up the fixture, for example, opens a network connection.
+		 * This method is called before a test is executed.
+		 */
+		protected function setUp()
+		{
+			$this->pixie = new \PHPixie\Pixie();
+			$this->pixie->app_namespace = "";
+			$this->object = new \PHPixie\Request(
+				$this->pixie,
+				new \PHPixie\Route('test',array(),array()),
+				'GET', 
+				array('fairy_post' => 'Trixie', 'xss' => 'a<div></div>','xss_arr'=>array(array('a<div></div>'))), 
+				array('fairy_get' => 'Trixie', 'xss' => 'a<div></div>', 'xss_arr' => array(array('a<div></div>'))), 
+				array('controller' => 'TestController', 'action' => 'index', 'fairy_param' => 'Trixie'),
+				array('fairy_server' => 'Trixie','HTTP_HOST'=>'phpixie.com','REQUEST_URI'=>'/test/?test=test')
+			);
+		}
+
+		/**
+		 * Tears down the fixture, for example, closes a network connection.
+		 * This method is called after a test is executed.
+		 */
+		protected function tearDown()
+		{
+
+		}
+		
+		/**
+		 * @covers Request::filter_xss
+		 * 
+		 */
+		public function testFilter_Xss()
+		{
+			$this->assertEquals($this->object->filter_xss('a<div></div>'), 'a');
+			$this->assertEquals(current(current($this->object->filter_xss(array(array('a<div></div>'))))), 'a');
+		}
+
+		/**
+		 * @covers Request::get
+		 * @todo   Implement testGet().
+		 */
+		public function testGet()
+		{
+			$this->assertEquals($this->object->get('fairy_get'), 'Trixie');
+			$this->assertEquals($this->object->get('bogus', 'default'), 'default');
+			$this->assertEquals($this->object->get('xss'), 'a');
+			$this->assertEquals($this->object->get('xss', null, false), 'a<div></div>');
+			$this->assertEquals(current(current($this->object->get('xss_arr', null, false))), 'a<div></div>');
+			$this->assertEquals(current(current($this->object->get('xss_arr'))), 'a');
+		}
+
+		/**
+		 * @covers Request::post
+		 * @todo   Implement testPost().
+		 */
+		public function testPost()
+		{
+			$this->assertEquals($this->object->post('fairy_post'), 'Trixie');
+			$this->assertEquals($this->object->post('bogus', 'default'), 'default');
+			$this->assertEquals($this->object->post('xss'), 'a');
+			$this->assertEquals($this->object->post('xss', null, false), 'a<div></div>');
+			$this->assertEquals(current(current($this->object->post('xss_arr', null, false))), 'a<div></div>');
+			$this->assertEquals(current(current($this->object->post('xss_arr'))), 'a');
+		}
+
+		/**
+		 * @covers Request::server
+		 * @todo   Implement testServer().
+		 */
+		public function testServer()
+		{
+			$this->assertEquals($this->object->server('fairy_server'), 'Trixie');
+			$this->assertEquals($this->object->server('bogus', 'default'), 'default');
+		}
+
+		/**
+		 * @covers Request::param
+		 * @todo   Implement testParam().
+		 */
+		public function testParam()
+		{
+			$this->assertEquals($this->object->param('fairy_param'), 'Trixie');
+			$this->assertEquals($this->object->param('bogus', 'default'), 'default');
+		}
+
+		/**
+		 * @covers Request::execute
+		 * @todo   Implement testExecute().
+		 */
+		public function testExecute()
+		{
+			$this->object->execute();
+		}
+
+		/**
+		 * @covers Request::url
+		 */
+		public function testUrl()
+		{
+			$this->assertEquals('http://phpixie.com/test/', $this->object->url());
+			$this->assertEquals('http://phpixie.com/test/?test=test', $this->object->url(true));
+			$this->object = new \PHPixie\Request($this->pixie, $this->object->route, 'GET', array(), array(), array(),
+				array('HTTPS' => 'on','HTTP_HOST'=>'phpixie.com','REQUEST_URI'=>'/test/?test=test')
+			);
+			$this->assertEquals('https://phpixie.com/test/', $this->object->url());
+			$this->assertEquals('https://phpixie.com/test/?test=test', $this->object->url(true));
+			
+		}
+		/**
+		 * @covers Request::execute
+		 * @todo   Implement testExecute().
+		 */
+		public function testExecuteException()
+		{
+			$req = new \PHPixie\Request(
+				$this->pixie,
+				new \PHPixie\Route('test',array(),array()),
+				'GET', 
+				array('fairy_post' => 'Trixie', 'xss' => 'a<div></div>','xss_arr'=>array(array('a<div></div>'))), 
+				array('fairy_get' => 'Trixie', 'xss' => 'a<div></div>', 'xss_arr' => array(array('a<div></div>'))), 
+				array('controller' => 'bogus', 'action' => 'index', 'fairy_param' => 'Trixie'),
+				array('fairy_server' => 'Trixie','HTTP_HOST'=>'phpixie.com','REQUEST_URI'=>'/test/?test=test')
+			);
+			$except = false;
+			try {
+				$req->execute();
+			} catch (Exception $e) {
+				$except = true;
+			}
+			$this->assertEquals($except, true);
+		}
+
+	}
+}

+ 66 - 0
php-phpixie/vendor/phpixie/core/tests/responseTest.php

@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013 - 02 - 05 at 23:08:34.
+ */
+class ResponseTest extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Response
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$this->object = new \PHPixie\Response;
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+
+	}
+
+	/**
+	 * @covers Response::add_header
+	 * @todo   Implement testAdd_header().
+	 */
+	public function testAdd_header()
+	{
+		$this->object->add_header('test');
+		$this->assertEquals(end($this->object->headers), 'test');
+	}
+
+	/**
+	 * @covers Response::redirect
+	 * @todo   Implement testRedirect().
+	 */
+	public function testRedirect()
+	{
+		$this->object->redirect('http://google.com');
+		$this->assertContains('Location: http://google.com', $this->object->headers);
+	}
+
+	/**
+	 * @covers Response::send_body
+	 * @todo   Implement testSend_body().
+	 */
+	public function testSend_body()
+	{
+		$this->object->body = 'test';
+		ob_start();
+		$this->object->send_body();
+		$out = ob_get_contents();
+		ob_end_clean();
+		$this->assertEquals($out, 'test');
+	}
+
+}

+ 43 - 0
php-phpixie/vendor/phpixie/core/tests/routeTest.php

@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-02-10 at 16:36:42.
+ */
+class RoteTest extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Route
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$this->object = new \PHPixie\Route('url', '(/<controller>(/<action>(/<id>)))', array(
+			'controller' => 'home',
+			'action' => 'index'
+		),'test');
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+
+	}
+
+	public function testUrl()
+	{
+
+		$this->assertEquals('/home/index/5', $this->object->url(array('id' => 5)));
+		$this->assertEquals('/home/index', $this->object->url());
+		$this->assertEquals('TEST', $this->object->methods[0]);
+	}
+
+}

+ 132 - 0
php-phpixie/vendor/phpixie/core/tests/routerTest.php

@@ -0,0 +1,132 @@
+<?php
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-02-10 at 16:36:42.
+ */
+class RoterTest extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Router
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$this->object=new \PHPixie\Router(new \PHPixie\Pixie);
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+
+	}
+
+	/**
+	 * @covers Route::get
+	 * @todo   Implement testGet().
+	 */
+	public function testGet()
+	{
+		$except = false;
+		$this->object->add(new \PHPixie\Route('a', 'b', array()));
+		try {
+			$this->object->get('c');
+		} catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true, $except);
+	}
+
+	/**
+	 * @covers Route::match
+	 * @todo   Implement testMatch().
+	 */
+	public function testMatchFunc()
+	{
+		$this->object->add(new \PHPixie\Route('func', function() {
+				return array('action' => 'index');
+			}, array('controller' => 'home')));
+		$route = $this->object->match('/test');
+		$this->assertEquals('func',  $route['route']->name);
+		$this->assertEquals('index', $route['params']['action']);
+		$this->assertEquals('home', $route['params']['controller']);
+	}
+
+	/**
+	 * @covers Route::match
+	 * @todo   Implement testMatch().
+	 */
+	public function testMatchDefault()
+	{
+		$this->object->add(new \PHPixie\Route('default', '(/<controller>(/<action>(/<id>)))', array(
+			'controller' => 'home',
+			'action' => 'index'
+		)));
+		$route = $this->object->match('/');
+		$this->assertEquals('default', $route['route']->name);
+		$this->assertEquals('index', $route['params']['action']);
+		$this->assertEquals('home', $route['params']['controller']);
+
+		$route = $this->object->match('/test');
+		$this->assertEquals('default', $route['route']->name);
+		$this->assertEquals('index', $route['params']['action']);
+		$this->assertEquals('test', $route['params']['controller']);
+
+		$route = $this->object->match('/test/act');
+		$this->assertEquals('default', $route['route']->name);
+		$this->assertEquals('act', $route['params']['action']);
+		$this->assertEquals('test', $route['params']['controller']);
+
+		$route = $this->object->match('/test/act/8');
+		$this->assertEquals('default', $route['route']->name);
+		$this->assertEquals('act', $route['params']['action']);
+		$this->assertEquals('test', $route['params']['controller']);
+		$this->assertEquals(8, $route['params']['id']);
+	}
+
+	/**
+	 * @covers Route::match
+	 * @todo   Implement testMatch().
+	 */
+	public function testMatchCustom()
+	{
+		$this->object->add(new \PHPixie\Route('default', array('/<alpha><num>', array(
+				'alpha' => '[a-z]*',
+				'num' => '[0-9]*'
+			)), array(
+			'controller' => 'home',
+			'action' => 'index'
+		)));
+		$route = $this->object->match('/test123');
+		$this->assertEquals('default', $route['route']->name);
+		$this->assertEquals('index', $route['params']['action']);
+		$this->assertEquals('home', $route['params']['controller']);
+		$this->assertEquals('test', $route['params']['alpha']);
+		$this->assertEquals(123, $route['params']['num']);
+	}
+	
+	public function testMatchMethod() {
+		$this->object->add(new \PHPixie\Route('get', '/url', array(
+			'controller' => 'home',
+			'action' => 'get'
+		), 'GeT'));
+		$this->object->add(new \PHPixie\Route('post', '/url', array(
+			'controller' => 'home',
+			'action' => 'get'
+		), array('PosT')));
+		$route = $this->object->match('/url', 'GEt');
+		$this->assertEquals('get', $route['route']->name);
+		$route = $this->object->match('/url', 'POST');
+		$this->assertEquals('post', $route['route']->name);
+	}
+
+
+}

+ 91 - 0
php-phpixie/vendor/phpixie/core/tests/sessionTest.php

@@ -0,0 +1,91 @@
+<?php
+require_once(ROOT.'/vendor/phpixie/core/classes/PHPixie/Session.php');
+/**
+ * Generated by PHPUnit_SkeletonGenerator on 2013 - 02 - 06 at 08:47:19.
+ * @runTestsInSeparateProcesses
+ */
+class sessionTest extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Session
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$this->object = new \PHPixie\Session(new \PHPixie\Pixie);
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+		session_destroy();
+	}
+
+	/**
+	 * @covers $this->object->get
+	 * @todo   Implement testGet().
+	 */
+	public function testGet()
+	{
+		session_start();
+		$_SESSION['test'] = 'TEST';
+		$this->assertEquals($this->object->get('test'), 'TEST');
+		$this->assertEquals($this->object->get('bogus', false), false);
+	}
+
+	/**
+	 * @covers $this->object->set
+	 * @todo   Implement testSet().
+	 */
+	public function testSet()
+	{
+		$this->object->set('testSet', 'test');
+		$this->assertArrayHasKey('testSet', $_SESSION);
+		$this->assertEquals('test', $_SESSION['testSet']);
+	}
+
+	/**
+	 * @covers $this->object->remove
+	 * @todo   Implement testRemove().
+	 */
+	public function testRemove()
+	{
+		session_start();
+		$_SESSION['test'] = 'TEST';
+		$this->object->remove('test');
+		$this->assertEquals(false, isset($_SESSION['test']));
+	}
+
+	/**
+	 * @covers $this->object->reset
+	 * @todo   Implement testReset().
+	 */
+	public function testReset()
+	{
+		session_start();
+		$_SESSION['test'] = 'TEST';
+		$this->object->reset();
+		$this->assertEquals(0, count($_SESSION));
+	}
+
+	/**
+	 * @covers $this->object->flash
+	 */
+	public function testFlash()
+	{
+		$this->object->flash('test', 'Trixie');
+		$this->object->flash('test', 'Tinkerbell');
+		$this->assertEquals('Tinkerbell', $this->object->flash('test'));
+		$this->assertEquals(null, $this->object->flash('test'));
+	}
+
+}

+ 54 - 0
php-phpixie/vendor/phpixie/core/tests/viewTest.php

@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator on 2013-02-05 at 09:23:37.
+ */
+class ViewTest extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var View
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$this->file = $file = tempnam(sys_get_temp_dir(), 'view');
+		file_put_contents($file, '<?php echo $fairy; ?>');
+		$pixie = $this->getMock("\\PHPixie\\Pixie", array('find_file'));
+		$pixie->expects($this->once())
+                 ->method('find_file')
+                 ->will($this->returnValue($this->file));
+		$this->object = new \PHPixie\View($pixie, 'view');
+	}
+
+	/**
+	 * @covers View::__set and View::__get
+	 */
+	public function test__set()
+	{
+		// Remove the following lines when you implement this test.
+		$this->object->fairy = 'Tinkerbell';
+		$this->assertEquals($this->object->fairy, 'Tinkerbell');
+	}
+
+	/**
+	 * @covers View::render
+	 */
+	public function testRender()
+	{
+
+		$this->object->fairy = 'Tinkerbell';
+		$out = $this->object->render();
+		$this->assertEquals('Tinkerbell', $out);
+	}
+	
+	public function tearDown(){
+		unlink($this->file);
+	}
+
+}

+ 4 - 0
php-phpixie/vendor/phpixie/db/README.md

@@ -0,0 +1,4 @@
+PHPixie-DB
+==========
+
+Database Drivers for PHPixie

+ 129 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB.php

@@ -0,0 +1,129 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * Database Module for PHPixie
+ *
+ * This module allows you to access the database. Currently
+ * PDO and Mysqli drivers are supported. PDO drivers can access Mysql, 
+ * SQLite and PostgreSQL databases.
+ *
+ * @see \PHPixie\DB\Query
+ * @package    DB
+ */
+class DB {
+	
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	public $pixie;
+	
+	/**
+	 * Database connection instances
+	 * @var \PHPixie\DB\Connection
+	 */
+	protected $db_instances = array();
+	
+	/**
+	 * Initializes the database module
+	 * 
+	 * @param \PHPixie\Pixie $pixie Pixie dependency container
+	 */
+	public function __construct($pixie) {
+		$this->pixie = $pixie;
+	}
+	
+	/**
+	 * Gets an instance of a connection to the database
+	 *
+	 * @param string  $config Configuration name of the connection.
+	 *                        Defaults to  'default'.
+	 * @return \PHPixie\DB\Connection  Driver implementation of the Connection class.
+	 */
+	public function get($config = 'default'){
+		if (!isset($this->db_instances[$config])) {
+			$driver = $this->pixie->config->get("db.{$config}.driver");
+			$driver = "\\PHPixie\\DB\\".$driver."\\Connection";
+			$this->db_instances[$config] = new $driver($this->pixie, $config);
+		}
+		return $this->db_instances[$config];
+	}
+	
+	/**
+	 * Builds a query for specified connection.
+	 *
+	 * @param string $type   Query type. Available types: select,update,insert,delete,count
+	 * @param string  $config Configuration name of the connection.
+	 *                        Defaults to  'default'.
+	 * @return \PHPixie\DB\Query  Driver implementation of the Query class.
+	 */
+	public function query($type, $config = 'default')
+	{
+		return $this->get($config)->query($type);
+	}
+
+	/**
+	 * Gets the id of the last inserted row
+	 *
+	 * @param string  $config Configuration name of the connection.
+	 *                        Defaults to  'default'.
+	 * @return mixed Id of the last inserted row
+	 */
+	public function insert_id($config = 'default')
+	{
+		return $this->get($config)->insert_id();
+	}
+	
+	/**
+	 * Gets column names for the specified table
+	 *
+	 * @param string $table Name of the table to get columns from
+	 * @param string  $config Configuration name of the connection.
+	 *                        Defaults to  'default'.
+	 * @return array Array of column names
+	 */
+	public function list_columns($table, $config = 'default') {
+		return $this->get($config)->list_columns($table);
+	}
+	
+	/**
+	 * Returns an Expression representation of the value.
+	 * Values wrapped inside Expression are not escaped in queries
+	 *
+	 * @param mixed $value Value to be wrapped
+	 * @return \PHPixie\Db\Expression  Raw value that will not be escaped during query building
+	 */
+	public function expr($value) {
+		return new \PHPixie\DB\Expression($value);
+	}
+	
+	/*
+	 * Creates a new query
+	 *
+	 * @param string $driver Database driver name
+	 * @param \PHPixie\DB\Connection $db   Database connection
+	 * @param string $type Query type. Available types: select, update, insert, delete, count
+	 * @return \PHPixie\DB\Query
+	 */
+	public function query_driver($driver, $db, $type) {
+		$driver = "\\PHPixie\\DB\\".$driver."\\Query";
+		return new $driver($db, $type);
+	}
+	
+	/*
+	 * Creates a new result
+	 *
+	 * @param string $driver Database driver name
+	 * @param object $cursor Datbase result cursor
+	 * @return \PHPixie\DB\Result
+	 */
+	public function result_driver($driver, $cursor) {
+		$driver = "\\PHPixie\\DB\\".$driver."\\Result";
+		return new $driver($cursor);
+	}
+	
+	
+		
+}

+ 92 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Connection.php

@@ -0,0 +1,92 @@
+<?php
+
+namespace PHPixie\DB;
+
+/**
+ * Database related functions. Creates connections,
+ * executes queries and returns results. It is also the
+ * generic connection class used by drivers.
+ * @package Database
+ */
+abstract class Connection
+{
+
+	public $pixie;
+	
+	public function __construct($pixie, $config) {
+		$this->pixie = $pixie;
+	}
+	
+	/**
+	 * Executes a prepared statement query
+	 *
+	 * @param string   $query  A prepared statement query
+	 * @param array     $params Parameters for the query
+	 * @return Result_Database
+	 * @see Result_Database
+	 */
+	public abstract function execute($query, $params = array());
+
+	/**
+	 * Builds a new Query to the database
+	 *
+	 * @param string $type Query type. Available types: select, update, insert, delete, count
+	 * @return Result_Database
+	 * @see Query_Database
+	 */
+	public abstract function query($type);
+
+	/**
+	 * Gets the id of the last inserted row.
+	 *
+	 * @return mixed The id of the last inserted row
+	 */
+	public abstract function insert_id();
+
+	/**
+	 * Gets column names for the specified table
+	 *
+	 * @param string $table Name of the table to get columns from
+	 * @return array Array of column names
+	 */
+	public abstract function list_columns($table);
+
+	/**
+	 * Executes a named query where parameters are passed as an associative array
+	 * Example:
+	 * <code>
+	 * $result=$db->namedQuery("SELECT * FROM fairies where name = :name",array('name'=>'Tinkerbell'));
+	 * </code>
+	 *
+	 * @param string $query  A named query
+	 * @param array   $params Associative array of parameters
+	 * @return Result_Database   Current drivers implementation of Result_Database
+	 */
+	public function named_query($query, $params = array())
+	{
+		$bind = array();
+		preg_match_all('#:(\w+)#is', $query, $matches, PREG_SET_ORDER);
+		foreach ($matches as $match)
+		{
+			if (isset($params[$match[1]]))
+			{
+				$query = preg_replace("#{$match[0]}#", '?', $query, 1);
+				$bind[] = $params[$match[1]];
+			}
+		}
+		return $this->execute($query, $bind);
+	}
+
+	/**
+	 * Returns an Expression representation of the value.
+	 * Values wrapped inside Expression are not escaped in queries
+	 *
+	 * @param mixed $value Value to be wrapped
+	 * @return \PHPixie\Db\Expression  Raw value that will not be escaped during query building
+	 */
+	public function expr($value)
+	{
+		return $this->phpixie->db->expr($value);
+	}
+
+}

+ 35 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Expression.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace PHPixie\DB;
+
+/**
+ * This class allows you to wrap fields or values that you don't want to be escaped
+ * inside the query
+ * @package Database
+ */
+class Expression
+{
+
+	/**
+	 * Part of query that should not be escaped
+	 * @var mixed
+	 */
+	public $value;
+
+	/**
+	 * Marks a part of query as a database specific expression,
+	 * e.g. calls to SQL functions like MAX(), SUBSTR() etc.
+	 * Example
+	 * <code>
+	 * $q->fields($this->pixie->db->expr('COUNT(*)'));
+	 * </code>
+	 *
+	 * @param mixed $value Part of query that should not be escaped
+	 * @return Expression_Database
+	 */
+	public function __construct($value)
+	{
+		$this->value = $value;
+	}
+
+}

+ 123 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Mysql/Connection.php

@@ -0,0 +1,123 @@
+<?php
+
+namespace PHPixie\DB\Mysql;
+
+/**
+ * Mysqli Database Implementation
+ * @package Database
+ */
+class Connection extends \PHPixie\DB\Connection
+{
+	
+	/**
+	 * Mysqli database connection object
+	 * @var mysqli
+	 * @link http://php.net/manual/en/class.mysqli.php
+	 */
+	public $conn;
+
+	/**
+	 * Type of the database, mysql.
+	 * @var string
+	 */
+	public $db_type = 'mysql';
+
+	/**
+	 * Initializes database connection
+	 *
+	 * @param string $config Name of the connection to initialize
+	 * @return void
+	 */
+	public function __construct($pixie, $config)
+	{
+		parent::__construct($pixie, $config);
+		
+		$this->conn = mysqli_connect(
+			$pixie->config->get("db.{$config}.host", 'localhost'),
+			$pixie->config->get("db.{$config}.user", ''),
+			$pixie->config->get("db.{$config}.password", ''),
+			$pixie->config->get("db.{$config}.db")
+		);
+		$this->conn->set_charset("utf8");
+	}
+
+	/**
+	 * Gets column names for the specified table
+	 *
+	 * @param string $table Name of the table to get columns from
+	 * @return array Array of column names
+	 * @throw \Exception if table doesn't exist
+	 */
+	public function list_columns($table)
+	{
+		$columns = array();
+		$table_desc = $this->execute("DESCRIBE `$table`");
+		if (!$table_desc->valid())
+		{
+			throw new \Exception("Table '{$table}' doesn't exist");
+		}
+		foreach ($table_desc as $column)
+		{
+			$columns[] = $column->Field;
+		}
+
+		return $columns;
+	}
+
+	/**
+	 * Builds a new Query implementation
+	 *
+	 * @param string $type Query type. Available types: select,update,insert,delete,count
+	 * @return Query_Mysql_Driver  Returns a Mysqli implementation of a Query.
+	 * @see Query_Database
+	 */
+	public function query($type)
+	{
+		return $this->pixie->db->query_driver('Mysql', $this, $type);
+	}
+
+	/**
+	 * Gets the id of the last inserted row.
+	 *
+	 * @return mixed Row id
+	 */
+	public function insert_id()
+	{
+		return $this->conn->insert_id;
+	}
+
+	/**
+	 * Executes a prepared statement query
+	 *
+	 * @param string   $query  A prepared statement query
+	 * @param array     $params Parameters for the query
+	 * @return Result_Mysql_Driver    Mysqli implementation of a database result
+	 * @throws \Exception If the query resulted in an error
+	 * @see Database_Result
+	 */
+	public function execute($query, $params = array())
+	{
+		$cursor = $this->conn->prepare($query);
+		if (!$cursor)
+			throw new \Exception("Database error: {$this->conn->error} \n in query:\n{$query}");
+		$types = '';
+		$bind = array();
+		$refs = array();
+		if (!empty($params))
+		{
+			foreach ($params as $key => $param)
+			{
+				$refs[$key] = is_array($param) ? $param[0] : $param;
+				$bind[] = &$refs[$key];
+				$types .= is_array($param) ? $param[1] : 's';
+			}
+			array_unshift($bind, $types);
+
+			call_user_func_array(array($cursor, 'bind_param'), $bind);
+		}
+		$cursor->execute();
+		$res = $cursor->get_result();
+		return $this->pixie->db->result_driver('Mysql', $res);
+	}
+
+}

+ 12 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Mysql/Query.php

@@ -0,0 +1,12 @@
+<?php
+
+namespace PHPixie\DB\Mysql;
+
+/**
+ * Mysqli implementation of the database Query
+ * @package Database
+ */
+class Query extends \PHPixie\DB\PDO\Query
+{
+
+}

+ 57 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Mysql/Result.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace PHPixie\DB\Mysql;
+
+/**
+ * Database result implementation for Mysqli
+ * @package Database
+ */
+class Result extends \PHPixie\DB\Result
+{
+
+	/**
+	 * Initializes new result object
+	 *
+	 * @param mysqli_result $result Mysqli Result
+	 * @return void
+	 * @link http://php.net/manual/en/class.mysqli-result.php
+	 */
+	public function __construct($result)
+	{
+		$this->_result = $result;
+	}
+
+	/**
+	 * Throws exception if rewind is attempted.
+	 *
+	 * @return void
+	 * @throws \Exception If rewind is attempted
+	 */
+	public function rewind()
+	{
+		if ($this->_position > 0)
+		{
+			throw new \Exception('Mysqli result cannot be rewound for unbuffered queries.');
+		}
+	}
+
+	/**
+	 * Iterates to the next row in the result set
+	 *
+	 * @return void
+	 */
+	public function next()
+	{
+		$this->check_fetched();
+		$this->_row = $this->_result->fetch_object();
+		if ($this->_row)
+		{
+			$this->_position++;
+		}
+		else
+		{
+			$this->_result->free();
+		}
+	}
+
+}

+ 132 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/PDO/Connection.php

@@ -0,0 +1,132 @@
+<?php
+
+namespace PHPixie\DB\PDO;
+
+/**
+ * PDO Database implementation.
+ * @package Database
+ */
+class Connection extends \PHPixie\DB\Connection
+{
+
+	public $pixie;
+	
+	/**
+	 * Connection object
+	 * @var PDO
+	 * @link http://php.net/manual/en/class.pdo.php
+	 */
+	public $conn;
+
+	/**
+	 * Type of the database, e.g. mysql, pgsql etc.
+	 * @var string
+	 */
+	public $db_type;
+
+	/**
+	 * Initializes database connection
+	 *
+	 * @param string $config Name of the connection to initialize
+	 * @return void
+	 */
+	public function __construct($pixie, $config)
+	{
+		parent::__construct($pixie, $config);
+		
+		$this->conn = new \PDO(
+			$pixie->config->get("db.{$config}.connection"),
+			$pixie->config->get("db.{$config}.user", ''),
+			$pixie->config->get("db.{$config}.password", '')
+		);
+		$this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+		$this->db_type = strtolower(str_replace('PDO_', '', $this->conn->getAttribute(\PDO::ATTR_DRIVER_NAME)));
+		if ($this->db_type != 'sqlite')
+		{
+			$this->conn->exec("SET NAMES utf8");
+		}
+	}
+
+	/**
+	 * Builds a new Query implementation
+	 *
+	 * @param string $type Query type. Available types: select,update,insert,delete,count
+	 * @return Query_PDO_Driver  Returns a PDO implementation of a Query.
+	 * @see Query_Database
+	 */
+	public function query($type)
+	{
+		return $this->pixie->db->query_driver('PDO', $this, $type);
+	}
+
+	/**
+	 * Gets the id of the last inserted row.
+	 *
+	 * @return mixed Row id
+	 */
+	public function insert_id()
+	{
+		if ($this->db_type == 'pgsql')
+		{
+			return $this->execute('SELECT lastval() as id')->current()->id;
+		}
+		return $this->conn->lastInsertId();
+	}
+
+	/**
+	 * Gets column names for the specified table
+	 *
+	 * @param string $table Name of the table to get columns from
+	 * @return array Array of column names
+	 */
+	public function list_columns($table)
+	{
+		$columns = array();
+		if ($this->db_type == 'mysql')
+		{
+			$table_desc = $this->execute("DESCRIBE `$table`");
+			foreach ($table_desc as $column)
+			{
+				$columns[] = $column->Field;
+			}
+		}
+		if ($this->db_type == 'pgsql')
+		{
+			$table_desc = $this->execute("select column_name from information_schema.columns where table_name = '{$table}' and table_catalog=current_database();");
+			foreach ($table_desc as $column)
+			{
+				$columns[] = $column->column_name;
+			}
+		}
+		if ($this->db_type == 'sqlite')
+		{
+			$table_desc = $this->execute("PRAGMA table_info('$table')");
+			foreach ($table_desc as $column)
+			{
+				$columns[] = $column->name;
+			}
+		}
+		return $columns;
+	}
+
+	/**
+	 * Executes a prepared statement query
+	 *
+	 * @param string   $query  A prepared statement query
+	 * @param array     $params Parameters for the query
+	 * @return Result_PDO_Driver    PDO implementation of a database result
+	 * @throws \Exception If the query resulted in an error
+	 * @see Database_Result
+	 */
+	public function execute($query, $params = array())
+	{
+		$cursor = $this->conn->prepare($query);
+		if (!$cursor->execute($params))
+		{
+			$error = $cursor->errorInfo();
+			throw new Exception("Database error:\n".$error[2]." \n in query:\n{$query}");
+		}
+		return $this->pixie->db->result_driver('PDO', $cursor);
+	}
+
+}

+ 393 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/PDO/Query.php

@@ -0,0 +1,393 @@
+<?php
+
+namespace PHPixie\DB\PDO;
+
+/**
+ * PDO implementation of the database Query
+ * @package Database
+ */
+class Query extends \PHPixie\DB\Query
+{
+
+	/**
+	 * Type of the database, e.g. mysql, pgsql etc.
+	 * @var string
+	 */
+	protected $_db_type;
+
+	/**
+	 * Character to use for quoting fields
+	 * @var string
+	 */
+	protected $_quote;
+
+	/**
+	 * Creates a new query object, checks which driver we are using and set the character used for quoting
+	 *
+	 * @param DB $db   Database connection
+	 * @param string $type Query type. Available types: select, update, insert, delete, count
+	 * @return void
+	 * @see \PHPixie\DB\Query::__construct()
+	 */
+	public function __construct($db, $type)
+	{
+		parent::__construct($db, $type);
+		$this->_db_type = $this->_db->db_type;
+		$this->_quote = $this->_db_type == 'mysql' ? '`' : '"';
+	}
+
+	/**
+	 * Puts quotes around a string
+	 *
+	 * @param string $str     String to be enclosed in quotes
+	 * @return string  String surrounded with quotes
+	 */
+	protected function quote($str)
+	{
+		return $this->_quote.$str.$this->_quote;
+	}
+
+	/**
+	 * If a string is passed escapes a field by enclosing it in specified quotes.
+	 * If you pass an \PHPixie\DB\Expression object the value will be inserted into the query unescaped
+	 *
+	 * @param mixed $field     Field to be escaped or an \PHPixie\DB\Expression object
+	 *                         if the field must not be escaped
+	 * @return string  Escaped field representation
+	 * @see \PHPixie\DB\Expression
+	 */
+	public function escape_field($field)
+	{
+		if (is_object($field) && $field instanceof \PHPixie\DB\Expression)
+		{
+			return $field->value;
+		}
+		$field = explode('.', $field);
+		if (count($field) == 1)
+		{
+			array_unshift($field, $this->last_alias());
+		}
+		$str = $this->quote($field[0]).'.';
+		if (trim($field[1]) == '*')
+		{
+			return $str.'*';
+		}
+		return $str.$this->quote($field[1]);
+	}
+
+	/**
+	 * Replaces the value with ? and appends it to the parameters array
+	 * If you pass an \PHPixie\DB\Expression object the value will be inserted into the query unescaped
+	 * @param mixed $val     Value to be escaped or an \PHPixie\DB\Expression object
+	 *                       if the value must not be escaped
+	 * @param array  &$params Reference to parameters array
+	 * @return string  Escaped value representation
+	 */
+	public function escape_value($val, &$params)
+	{
+		if ($val instanceof \PHPixie\DB\Expression)
+		{
+			return $val->value;
+		}
+		if ($val instanceof \PHPixie\DB\Query)
+		{
+			return $this->subquery($val, $params);
+		}
+		$params[] = $val;
+		return '?';
+	}
+
+	/**
+	 * Gets the SQL for a subquery and appends its parameters to current ones
+	 *
+	 * @param \PHPixie\DB\Query $query Query builder for the subquery
+	 * @param array  &$params Reference to parameters array
+	 * @return string  Subquery SQL
+	 */
+	protected function subquery($query, &$params)
+	{
+		$query = $query->query();
+		$params = array_merge($params, $query[1]);
+		return "({$query[0]}) ";
+	}
+
+	/**
+	 * Gets the SQL for a table to select from
+	 *
+	 * @param string|\PHPixie\DB\Expression|\PHPixie\DB\Query|array $table Table representation
+	 * @param array  &$params Reference to parameters array
+	 * @param string &alias   Alias for this table
+	 * @return string  Table SQL
+	 */
+	public function escape_table($table, &$params)
+	{
+		$alias = null;
+		if (is_array($table))
+		{
+			$alias = $table[1];
+			$table = $table[0];
+		}
+
+		if (is_string($table))
+		{
+			$table = $this->quote($table);
+			if ($alias != null)
+				$table.= " AS {$alias}";
+			return $table;
+		}
+
+		if ($alias == null)
+			$alias = $this->last_alias();
+
+		if ($table instanceof \PHPixie\DB\Query)
+			return "{$this->subquery($table, $params)} AS {$alias}";
+
+		if ($table instanceof \PHPixie\DB\Expression)
+			return "({$table->value}) AS {$alias}";
+
+		throw new \Exception("Parameter type {get_class($table)} cannot be used as a table");
+	}
+
+	/**
+	 * Builds a query and fills the $params array with parameter values
+	 *
+	 * @return array     An array with a prepared query string and an array of parameters
+	 */
+	public function query()
+	{
+
+		$query = '';
+		$params = array();
+
+		if ($this->_type == 'insert')
+		{
+			$query .= "INSERT INTO {$this->quote($this->_table)} ";
+			if (empty($this->_data) && $this->_db_type == 'pgsql')
+			{
+				$query.= "DEFAULT VALUES ";
+			}
+			else
+			{
+				$columns = '';
+				$values = '';
+				$first = true;
+				foreach ($this->_data as $key => $val)
+				{
+					if (!$first)
+					{
+						$values .= ', ';
+						$columns .= ', ';
+					}
+					else
+					{
+						$first = false;
+					}
+					$columns .= $this->quote($key);
+					$values .= $this->escape_value($val, $params);
+				}
+				$query .= "({$columns}) VALUES({$values})";
+			}
+		}
+		else
+		{
+			if ($this->_type == 'select')
+			{
+				$query .= "SELECT ";
+				if ($this->_fields == null)
+				{
+					$query .= "* ";
+				}
+				else
+				{
+					$first = true;
+					foreach ($this->_fields as $f)
+					{
+						if (!$first)
+						{
+							$query .= ", ";
+						}
+						else
+						{
+							$first = false;
+						}
+						if (is_array($f))
+						{
+							$query .= "{$this->escape_field($f[0])} AS {$f[1]} ";
+						}
+						else
+						{
+							$query .= "{$this->escape_field($f)} ";
+						}
+					}
+				}
+				$query .= "FROM {$this->escape_table($this->_table, $params)} ";
+			}
+			if ($this->_type == 'count')
+			{
+				$query .= "SELECT COUNT(*) as {$this->quote('count')} FROM {$this->escape_table($this->_table, $params)} ";
+			}
+
+			if ($this->_type == 'delete')
+			{
+				if ($this->_db_type != 'sqlite')
+				{
+					$query .= "DELETE {$this->last_alias()}.* FROM {$this->quote($this->_table)} ";
+				}
+				else
+				{
+					if (!empty($this->_joins))
+					{
+						throw new \Exception("SQLite doesn't support deleting a table with JOIN in the query");
+					}
+					$query .= "DELETE FROM {$this->quote($this->_table)} ";
+				}
+			}
+			if ($this->_type == 'update')
+			{
+				$query .= "UPDATE {$this->quote($this->_table)} SET ";
+				$first = true;
+				foreach ($this->_data as $key => $val)
+				{
+					if (!$first)
+					{
+						$query.=", ";
+					}
+					else
+					{
+						$first = false;
+					}
+					$query .= "{$this->quote($key)} = {$this->escape_value($val, $params)}";
+				}
+				$query .= " ";
+			}
+
+			foreach ($this->_joins as $join)
+			{
+				$table = $join[0];
+				$table = $this->escape_table($table, $params);
+				$query .= strtoupper($join[1])." JOIN {$table} ON {$this->get_condition_query($join[2], $params, true, true)} ";
+			}
+
+			if (!empty($this->_conditions))
+			{
+				$query .= "WHERE {$this->get_condition_query($this->_conditions, $params, true)} ";
+			}
+			if (($this->_type == 'select' || $this->_type == 'count') && $this->_group_by != null)
+			{
+				$query .= "GROUP BY {$this->escape_field($this->_group_by)} ";
+			}
+			if (($this->_type == 'select' || $this->_type == 'count') && !empty($this->_having))
+			{
+				$query .= "HAVING {$this->get_condition_query($this->_having, $params, true)} ";
+			}
+
+			if ($this->_type == 'select' && !empty($this->_order_by))
+			{
+				$query .= "ORDER BY ";
+				$first = true;
+				foreach ($this->_order_by as $order)
+				{
+					if (!$first)
+					{
+						$query .= ',';
+					}
+					else
+					{
+						$first = false;
+					}
+					$query .= $this->escape_field($order[0])." ";
+					if (isset($order[1]))
+					{
+						$dir = strtoupper($order[1]);
+						$query .= $dir." ";
+					}
+				}
+			}
+
+			if (count($this->_union) > 0 && ($this->_type == 'select'))
+			{
+				$query = "({$query}) ";
+				foreach ($this->_union as $union)
+				{
+					$query .= $union[1] ? "UNION ALL " : "UNION ";
+					if ($union[0] instanceof \PHPixie\DB\Query)
+					{
+						$query .= $this->subquery($union[0], $params);
+					}
+					elseif ($union[0] instanceof \PHPixie\DB\Expression)
+					{
+						$query .= "({$union[0]->value}) ";
+					}
+					else
+					{
+						throw new \Exception("You can only use query builder instances or \$pixie->db->expr() for unions");
+					}
+				}
+			}
+
+			if ($this->_type != 'count')
+			{
+				if ($this->_limit != null)
+				{
+					$query .= "LIMIT {$this->_limit} ";
+				}
+				if ($this->_offset != null)
+				{
+					$query .= "OFFSET {$this->_offset} ";
+				}
+			}
+		}
+
+		return array($query, $params);
+	}
+
+	/**
+	 * Recursively parses conditions array into a query string
+	 *
+	 * @param array     $p                   Element of the cobditions array
+	 * @param array   &$params             Reference to parameters array
+	 * @param boolean   $skip_first_operator Flag to skip the first logical operator in a query
+	 *                                       to prevent AND or OR to be at the beginning of the query
+	 * @param boolean   $value_is_field      Flag if the the value in the logical operations should
+	 *                                       be treated as a field. E.g. for joins where the fields are
+	 *                                       compared between themselves and not with actual values
+	 * @return string     String representation of the conditions
+	 * @throws \Exception If condition cannot be parsed
+	 */
+	public function get_condition_query($p, &$params, $skip_first_operator, $value_is_field = false)
+	{
+		if (isset($p['field']))
+		{
+			if ($value_is_field)
+			{
+				$param = $this->escape_field($p['value']);
+			}
+			else
+			{
+				$param = $this->escape_value($p['value'], $params);
+			}
+			return $this->escape_field($p['field']).' '.$p['operator'].' '.$param;
+		}
+		if (isset($p['logic']))
+		{
+			return ($skip_first_operator ? '' : strtoupper($p['logic']).' ')
+				.$this->get_condition_query($p['conditions'], $params, false, $value_is_field);
+		}
+
+		$conds = '';
+		$skip = $skip_first_operator || (count($p) > 1);
+		foreach ($p as $q)
+		{
+			$conds .= $this->get_condition_query($q, $params, $skip, $value_is_field).' ';
+			$skip = false;
+		}
+		if (count($p) > 1 && !$skip_first_operator)
+		{
+			return "( ".$conds.")";
+		}
+		return $conds;
+
+		throw new \Exception("Cannot parse condition:\n".var_export($p, true));
+	}
+
+}

+ 57 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/PDO/Result.php

@@ -0,0 +1,57 @@
+<?php
+
+namespace PHPixie\DB\PDO;
+
+/**
+ * Database result implementation for PDO
+ * @package Database
+ */
+class Result extends \PHPixie\DB\Result
+{
+
+	/**
+	 * Initializes new result object
+	 *
+	 * @param PDOStatement $stmt PDO Statement
+	 * @return void
+	 * @link http://php.net/manual/en/class.pdostatement.php
+	 */
+	public function __construct($stmt)
+	{
+		$this->_result = $stmt;
+	}
+
+	/**
+	 * Throws exception if rewind is attempted.
+	 *
+	 * @return void
+	 * @throws \Exception If rewind is attempted
+	 */
+	public function rewind()
+	{
+		if ($this->_position > 0)
+		{
+			throw new \Exception('PDO statement cannot be rewound for unbuffered queries');
+		}
+	}
+
+	/**
+	 * Iterates to the next row in the result set
+	 *
+	 * @return void
+	 */
+	public function next()
+	{
+		$this->check_fetched();
+		$this->_row = $this->_result->fetchObject();
+		if ($this->_row)
+		{
+			$this->_position++;
+		}
+		else
+		{
+			$this->_result->closeCursor();
+		}
+	}
+
+}

+ 445 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Query.php

@@ -0,0 +1,445 @@
+<?php
+
+namespace PHPixie\DB;
+
+/**
+ * Query builder. It allows building queries by using methods to set specific query parameters.
+ * Database drivers extend this class so that they can generate database specific queries.
+ * The idea is to provide a database agnostic interface to query writing.
+ *
+ * @method mixed table(string $table = null) Set table to query.
+ *               Without arguments returns current table, returns self otherwise.
+ *
+ * @method mixed data(array $data = null) Set data for insert or update queries.
+ *               Without arguments returns current data, returns self otherwise.
+ *
+ * @method mixed limit(int $limit = null) Set number of rows to return. If NULL is passed than no limit is used.
+ *               If NULL is passed than no limit is used.
+ *               Without arguments returns current limit, returns self otherwise.
+ *
+ * @method mixed offset(string $offset = null) Set the offset for the first row in result.
+ *               If NULL is passed than no offset is used.
+ *               Without arguments returns current offset, returns self otherwise.
+ *
+ * @method mixed group_by(string $group_by = null) A column to group rows by for aggregator functions.
+ *               If NULL is passed than no grouping is done.
+ *               Without arguments returns current group_by argument, returns self otherwise.
+ *
+ * @method mixed type(string $type = null) Set query type. Available types: select, update, insert, delete, count.
+ *               Without arguments returns current type argument, returns self otherwise.
+ * @package Database
+ */
+
+abstract class Query
+{
+
+	/**
+	 * Array of conditions that rows must meet
+	 * @var array
+	 */
+	protected $_conditions = array();
+
+	/**
+	 * Table to query
+	 * @var unknown
+	 */
+	protected $_table;
+
+	/**
+	 * Fields to return in the query
+	 * @var array
+	 */
+	protected $_fields;
+
+	/**
+	 * Data for row insertion or update
+	 * @var unknown
+	 */
+	protected $_data;
+
+	/**
+	 * Query type. Available types: select, update, insert, delete, count
+	 * @var string
+	 */
+	protected $_type;
+
+	/**
+	 * Parameters for tables to join
+	 * @var array
+	 */
+	protected $_joins = array();
+
+	/**
+	 * Number of rows to return
+	 * @var int
+	 */
+	protected $_limit;
+
+	/**
+	 * Offset of the first row
+	 * @var int
+	 */
+	protected $_offset;
+
+	/**
+	 * Columns and directions to order by
+	 * @var array
+	 */
+	protected $_order_by = array();
+
+	/**
+	 * Database connection
+	 * @var DB
+	 */
+	protected $_db;
+
+	/**
+	 * Conditions for aggregator functions
+	 * @var array
+	 */
+	protected $_having = array();
+
+	/**
+	 * Column to group by for aggregator functions
+	 * @var string
+	 */
+	protected $_group_by;
+
+	/**
+	 * Last alias used on the table
+	 * @var string
+	 */
+	protected $_alias = null;
+
+	/**
+	 * Methods and type of value they allow that are available via __call
+	 * @var array
+	 */
+	protected $methods = array('data' => 'array', 'limit' => array('integer', 'NULL'), 'offset' => array('integer', 'NULL'), 'group_by' => array('string', 'NULL'), 'type' => 'string');
+
+	/**
+	 * UNION queries
+	 * @var array
+	 */
+	protected $_union = array();
+
+	/**
+	 * Generates a query in format that can be executed on current database implementation
+	 *
+	 */
+	public abstract function query();
+
+	/**
+	 * Creates a new query
+	 *
+	 * @param DB $db   Database connection
+	 * @param string $type Query type. Available types: select, update, insert, delete, count
+	 * @return void
+	 */
+	public function __construct($db, $type)
+	{
+		$this->_db = $db;
+		$this->_type = $type;
+	}
+
+	/**
+	 * Sets fields to be queried from the database. You can add aliases to the fields
+	 * by passing them as:
+	 *
+	 * array('field_name','alias')
+	 *
+	 * Example: $query->fields('id', array('name', 'fairy_name'))
+	 *
+	 * @param mixed   $field,...   Fields to be selected from the table
+	 * @return mixed  If no parameters are passed returns current array of fields,
+	 *                otherwise returns self.
+	 */
+	public function fields()
+	{
+		$p = func_get_args();
+		if (empty($p))
+		{
+			return $this->_fields;
+		}
+		else
+		{
+			$this->_fields = $p;
+		}
+		return $this;
+	}
+
+	/**
+	 * Sets the table to perform operations on, also supports subqueries
+	 *
+	 * @param string|Query_database|Expression_database $table table to select from
+	 * @param string $alias Alias for this table
+	 * @return mixed Returns self if a table is passed, otherwise returns the table
+	 */
+	public function table($table = null, $alias = null)
+	{
+		if ($table == null)
+		{
+			return is_array($this->_table) ? $this->_table[1] : $this->_table;
+		}
+
+		if (!is_string($table) && $alias == null)
+		{
+
+			$alias = $this->add_alias();
+		}
+		$this->_table = $alias == null ? $table : array($table, $alias);
+
+		return $this;
+	}
+
+	/**
+	 * Magic methods to create methods for all generic query parts
+	 *
+	 * @param string    $method Name of the method to call
+	 * @param array     $args   Array of parameters
+	 * @return mixed    If no arguments are passed returns the current value of the property,
+	 *                  otherwise returns self.
+	 * @throws \Exception If method doesn't exist
+	 * @throws \Exception If value is of incorrect type
+	 * @see $methods
+	 */
+
+	public function __call($method, $args)
+	{
+		if (isset($this->methods[$method]))
+		{
+			$property = '_'.$method;
+
+			if (empty($args))
+			{
+				return $this->$property;
+			}
+			$val = $args[0];
+			if (is_numeric($val))
+			{
+				$val = (int) $val;
+			}
+			$allowed_types = $this->methods[$method];
+			if (!is_array($allowed_types))
+			{
+				$allowed_types = array($allowed_types);
+			}
+			if (!in_array(gettype($val), $allowed_types))
+			{
+				throw new \Exception("Method '{$method}' only accepts values of type: ".implode(' or ', $allowed_types).", '{$val}' was passed");
+			}
+			$this->$property = $val;
+			return $this;
+		}
+		throw new \Exception("Method '{$method}' doesn't exist.");
+	}
+
+	/**
+	 * Executes the query
+	 *
+	 * @return object Executes current query on its database connection
+	 * @see DB
+	 */
+	public function execute()
+	{
+		$query = $this->query();
+		$result = $this->_db->execute($query[0], $query[1]);
+		if ($this->_type == 'count')
+		{
+			return $result->get('count');
+		}
+		return $result;
+	}
+
+	/**
+	 * Adds a joined table to the query.
+	 *
+	 * @param string $table Table to join
+	 * @param array $conds Conditions to join tables on, same behavior as with where() method
+	 * @param string  $type  Type of join. Defaults to 'left'
+	 * @return Query_Database   Returns self
+	 * @see where()
+	 */
+	public function join($table, $conds, $type = 'left')
+	{
+		$this->_joins[] = array($table, $type, $this->get_condition_part($conds));
+		return $this;
+	}
+
+	/**
+	 * Sets conditions for aggregate functions, same behavior as with where() method
+	 *
+	 * @return Query_Database Returns self
+	 * @see where()
+	 */
+	public function having()
+	{
+		$p = func_get_args();
+		$cond = $this->get_condition_part($p);
+		$this->_having = array_merge($this->_having, array($cond));
+		return $this;
+	}
+
+	/**
+	 * Adds a column to ordering parameters.
+	 *
+	 * @param string $column Column to order by
+	 * @param string $dir Ordering direction.
+	 * @return Query_Database  Returns self
+	 * @throws \Exception If ordering direction isn't DESC or ASC
+	 */
+	public function order_by($column, $dir = 'ASC')
+	{
+		$dir = strtoupper($dir);
+		if ($dir != 'DESC' && $dir != 'ASC')
+		{
+			throw new \Exception("Invalid sorting direction {$dir} specified");
+		}
+		$this->_order_by[] = array($column, $dir);
+		return $this;
+	}
+
+	/**
+	 * Sets conditions for the query.
+	 * Can be called in many ways, examples:
+	 * Shorthand equals condition:
+	 * <code>
+	 * $q->where('name', 'Tinkerbell')
+	 * </code>
+	 * Conditions with operator:
+	 * <code>
+	 * $q->where('id', '>', 3)
+	 * </code>
+	 * OR logic:
+	 * <code>
+	 * $q->where('or', array('name', 'Tinkerbell'))
+	 * </code>
+	 * OR logic with operator
+	 * <code>
+	 * ->where('or', array('id', '>', 3))
+	 * </code>
+	 * Arrays represent brackets. e.g
+	 * <code>
+	 * $q->where('name', 'Tinkerbell')
+	 *   ->where('or', array(
+	 *        array('id', '>', 7),
+	 *        array('id', '<', 15)
+	 *   );
+	 * //Will produce "WHERE `name`='Tinkerbell' OR (`id` > 7 AND `id` < 15)"
+	 * </code>
+	 * Multiple calls to where() append new conditions to previous ones
+	 *
+	 * @param mixed $column Column name, logic parameter 'OR' or 'AND' or an array of conditions
+	 * @param mixed $operator Condition value, operator or an array of parameters
+	 * @param mixed $val Condition value
+	 *
+	 * @return Query_Database  Returns self
+	 */
+	public function where()
+	{
+		$p = func_get_args();
+		$cond = $this->get_condition_part($p);
+		$this->_conditions = array_merge($this->_conditions, array($cond));
+
+		return $this;
+	}
+
+	/**
+	 * Recursively builds condition arrays for methods like where(), having()
+	 *
+	 * @param array     $p Parameters passed to the method
+	 * @return array     Array in condition format
+	 * @throws \Exception If condition format is incorrect
+	 */
+	private function get_condition_part($p)
+	{
+		if (is_string($p[0]) && (strtolower($p[0]) == 'or' || strtolower($p[0]) == 'and') && isset($p[1]) && is_array($p[1]))
+		{
+			$cond = $this->get_condition_part($p[1]);
+			$cond['logic'] = strtolower($p[0]);
+			return $cond;
+		}
+
+		if (is_array($p[0]))
+		{
+			if (count($p) == 1)
+			{
+				return $this->get_condition_part($p[0]);
+			}
+			$conds = array();
+			foreach ($p as $q)
+			{
+				$conds[] = $this->get_condition_part($q);
+			}
+			if (count($conds) == 1)
+			{
+				return $conds;
+			}
+			return array('logic' => 'and', 'conditions' => $conds);
+		}
+
+		if ((is_string($p[0]) || $p[0] instanceof \PHPixie\DB\Expression) && isset($p[1]))
+		{
+			if (is_string($p[0]) && strpos($p[0], '.') === false)
+			{
+				$p[0] = $this->last_alias().'.'.$p[0];
+			}
+			return array(
+				'logic' => 'and',
+				'conditions' => array(
+					'field' => $p[0],
+					'operator' => isset($p[2]) ? $p[1] : '=',
+					'value' => isset($p[2]) ? $p[2] : $p[1]
+				)
+			);
+		}
+
+		throw new \Exception('Incorrect conditional statement passed');
+	}
+
+	/**
+	 * Adds a UNION to the query
+	 * 
+	 * @param  Query_Database|Expression_Database  $query Query for the UNION
+	 * @param  string $all whether to do a UNION ALL, e.g. keep duplicate rows
+	 * @return Query_Database  Returns self
+	 */
+	public function union($query,$all=true) {
+		$this->_union[] = array($query,$all);
+		return $this;
+	}
+	
+	/**
+	 * Gets last generated alias
+	 *
+	 * @return string  Last generated alias. If no alias were created returns table name.
+	 */
+	public function last_alias()
+	{
+		if ($this->_alias === null)
+		{
+			return $this->_table;
+		}
+		return 'a'.$this->_alias;
+	}
+
+	/**
+	 * Generates new alias. Useful for dynamically adding aliases to joins.
+	 * Alias is just a letter 'a' with an incremented number.
+	 *
+	 * @return string New alias
+	 */
+	public function add_alias()
+	{
+		if ($this->_alias === null)
+		{
+			$this->_alias = 0;
+		}
+		else
+		{
+			$this->_alias++;
+		}
+		return $this->last_alias();
+	}
+
+}

+ 113 - 0
php-phpixie/vendor/phpixie/db/classes/PHPixie/DB/Result.php

@@ -0,0 +1,113 @@
+<?php
+
+namespace PHPixie\DB;
+
+/**
+ * Allows to access database results in a unified way and
+ * provides iterator support, so it can be used inside loops like 'foreach'
+ * @package Database
+ */
+abstract class Result implements \Iterator
+{
+
+	/**
+	 * Current row number
+	 * @var integer
+	 */
+	protected $_position = -1;
+
+	/**
+	 * Database result object
+	 * @var mixed
+	 */
+	protected $_result;
+
+	/**
+	 * Current row
+	 * @var object
+	 */
+	protected $_row;
+
+	/**
+	 * If at least one row has been fetched
+	 * @var object
+	 */
+	protected $_fetched = false;
+
+	/**
+	 * Returns current row
+	 *
+	 * @return object Current row in result set
+	 */
+	public function current()
+	{
+		$this->check_fetched();
+		return $this->_row;
+	}
+
+	/**
+	 * Gets the number of the current row
+	 *
+	 * @return integer Row number
+	 */
+	public function key()
+	{
+		$this->check_fetched();
+		return $this->_position;
+	}
+
+	/**
+	 * Check if current row exists.
+	 *
+	 * @return bool True if row exists
+	 */
+	public function valid()
+	{
+		$this->check_fetched();
+		return $this->_row != null;
+	}
+
+	/**
+	 * Returns all rows as array
+	 *
+	 * @return array  Array of rows
+	 */
+	public function as_array()
+	{
+		$arr = array();
+		foreach ($this as $row)
+		{
+			$arr[] = $row;
+		}
+		return $arr;
+	}
+
+	/**
+	 * Checks if the rows from the result set have
+	 * been fetched at least once. If not fetches first row.
+	 *
+	 */
+	protected function check_fetched()
+	{
+		if (!$this->_fetched)
+		{
+			$this->_fetched = true;
+			$this->next();
+		}
+	}
+
+	/**
+	 * Gets a column from the current row in the set
+	 *
+	 * @param  string $column Column name
+	 * @return mixed  Column value
+	 */
+	public function get($column)
+	{
+		if ($this->valid() && isset($this->_row->$column))
+		{
+			return $this->_row->$column;
+		}
+	}
+
+}

+ 26 - 0
php-phpixie/vendor/phpixie/db/composer.json

@@ -0,0 +1,26 @@
+{
+    "name": "phpixie/db",
+    "description": "PHPixie Database library",
+    "keywords": ["database", "mysql", "postgresql", "sqlite"],
+    "homepage": "http://phpixie.com",
+    "type": "library",
+    "license": "BSD",
+    "authors": [
+        {
+            "name": "Roman Tsiupa",
+            "email": "[email protected]",
+            "homepage": "http://dracony.org"
+        }
+    ],
+    "require": {
+        "phpixie/core": "2.*@dev"
+    },
+    "autoload": {
+        "psr-0": {"PHPixie": "classes/"}
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "2.x-dev"
+        }
+    }
+}

+ 10 - 0
php-phpixie/vendor/phpixie/db/tests/bootstrap.php

@@ -0,0 +1,10 @@
+<?php
+if(!defined('INIT')) {	
+	define('ROOT',dirname(dirname(dirname(dirname(dirname(__FILE__))))));
+	$loader = require_once(ROOT.'/vendor/autoload.php');
+	$loader->add('PHPixie', ROOT.'/vendor/phpixie/core/classes/');
+	$loader->add('PHPixie', ROOT.'/vendor/phpixie/db/classes/');
+	$loader->add('PHPixie',ROOT.'/vendor/phpixie/orm/classes/');
+	define('INIT', true);
+}
+	

+ 81 - 0
php-phpixie/vendor/phpixie/db/tests/db/dbTest.php

@@ -0,0 +1,81 @@
+<?php
+
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator on 2013-02-07 at 10:14:10.
+ */
+class DB_Test extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Expression_Database
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		
+		$this->db_file = tempnam(sys_get_temp_dir(), 'test.sqlite');
+		$this->conf_file = tempnam(sys_get_temp_dir(), 'test.conf');
+		file_put_contents($this->db_file, '');
+		$db = new PDO('sqlite:'.$this->db_file);
+		$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+		$db->exec("CREATE TABLE fairies(id INT PRIMARY_KEY,name VARCHAR(255))");
+		$pixie = $this->getMock('\PHPixie\Pixie',array('find_file'));
+		$pixie->expects($this->any())
+                 ->method('find_file')
+                 ->will($this->returnValue($this->conf_file));
+		$pixie->db = $this->getMockBuilder('\PHPixie\DB')
+				->disableOriginalConstructor()
+				->getMock();
+		$pixie->db->expects($this->any())
+                 ->method('query_driver')
+                 ->will($this->returnValue(null));
+		$pixie->config->set('db.default.connection', 'sqlite:'.$this->db_file);
+		$pixie-> config->set('db.default.driver', 'pdo');
+		$this->object = new \PHPixie\DB($pixie);
+		$pixie-> db = $this->object;
+		$db = null;
+	}
+	
+	public function testGet() {
+		$this->object->get()->test = 'same';
+		$this->assertEquals('same', $this->object->get()->test);
+		$this->assertEquals('PHPixie\DB\PDO\Connection', get_class($this->object->get()));
+	}
+	
+	public function testQuery() {
+		$this->assertEquals('PHPixie\DB\PDO\Query', get_class($this->object->query('select')));
+	}
+	
+	public function testInsert_id()
+	{
+		$this->object->get()->execute("INSERT INTO fairies(name)values('Trixie')");
+		$this->assertEquals(1, $this->object->insert_id());
+	}
+
+	public function testList_columns()
+	{
+		$cols = $this->object->list_columns('fairies');
+		$this->assertContains('id', $cols);
+		$this->assertContains('name', $cols);
+	}
+	
+	public function testExpr() {
+		$this->assertEquals('PHPixie\DB\Expression', get_class($this->object->expr("test")));
+	}
+	
+	public function testQuery_driver() {
+		$this->assertEquals('PHPixie\DB\PDO\Query', get_class($this->object->query_driver('pdo',$this->object->get(),'select')));
+	}
+	
+	public function testResult_driver() {
+		$this->assertEquals('PHPixie\DB\PDO\Result', get_class($this->object->result_driver('pdo',null)));
+	}
+	
+	
+}

+ 41 - 0
php-phpixie/vendor/phpixie/db/tests/db/expressionTest.php

@@ -0,0 +1,41 @@
+<?php
+
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator on 2013-02-07 at 10:14:10.
+ */
+class Expression_Test extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Expression_Database
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$this->object = new \PHPixie\DB\Expression('test');
+	}
+
+	/**
+	 * @covers Expression_Database::__construct
+	 */
+	public function testConstruct()
+	{
+		$this->assertEquals('test', $this->object->value);
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+
+	}
+
+}

+ 25 - 0
php-phpixie/vendor/phpixie/db/tests/db/mysql/connectionTest.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-02-01 at 06:23:13.
+ */
+class Mysql_Connection_Test extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Query_Mysql_Driver
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	public function testClass()
+	{
+		$this->getMockBuilder('\PHPixie\DB\Mysql\Connection')
+				->disableOriginalConstructor()
+				->getMock();
+	}
+	
+}

+ 207 - 0
php-phpixie/vendor/phpixie/db/tests/db/mysql/queryTest.php

@@ -0,0 +1,207 @@
+<?php
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-02-01 at 06:23:13.
+ */
+class Query_Mysql_DriverTest extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Query_Mysql_Driver
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$stub = (object) array('db_type' => 'mysql');
+		$this->object = new \PHPixie\DB\Mysql\Query($stub, 'select');
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+
+	}
+
+	/**
+	 * @covers Query_Mysql_Driver::escape_field
+	 * @todo   Implement testEscape_field().
+	 */
+	public function testEscape_field()
+	{
+		$this->object->add_alias();
+		$this->assertEquals('test', $this->object->escape_field(new \PHPixie\DB\Expression('test')));
+		$this->assertEquals('`a0`.*', $this->object->escape_field('*'));
+		$this->assertEquals('`a0`.`test`', $this->object->escape_field('test'));
+		$this->assertEquals('`test`.`test`', $this->object->escape_field('test.test'));
+	}
+
+	/**
+	 * @covers Query_Mysql_Driver::escape_value
+	 * @todo   Implement testEscape_value().
+	 */
+	public function testEscape_value()
+	{
+		$params = array();
+		$this->assertEquals('test', $this->object->escape_value(new \PHPixie\DB\Expression('test'), $params));
+		$this->assertEquals('?', $this->object->escape_value('korova', $params));
+		$this->assertArrayHasKey(0, $params);
+		$this->assertEquals('korova', $params[0]);
+	}
+
+	/**
+	 * @covers Query_Mysql_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQuerySelect1()
+	{
+		$query = $this->object
+			->table('fairies')
+			->where('a', 7)
+			->where('b', '<', 8)
+			->where('c', '>', 3)
+			->where('or', array('d', '>', 11))
+			->where(array(
+				array('e', 9),
+				array('or', array(
+						array('f', 10),
+						array('g', 11),
+					)),
+				array('or', array(
+						array('h', 12),
+						array('or', array('i', 13)),
+					))
+			))
+			->order_by('id', 'desc')
+			->group_by('id')
+			->having('j', '<', new \PHPixie\DB\Expression('korova'))
+			->having('or', array('l', '>', 11))
+			->having(array(
+				array('m', 9),
+				array('or', array(
+						array('n', 10),
+						array('o', 11),
+					))
+			))
+			->limit(5)
+			->offset(6)
+			->query();
+		$this->assertEquals("SELECT * FROM `fairies` WHERE `fairies`.`a` = ? AND `fairies`.`b` < ? AND `fairies`.`c` > ? OR `fairies`.`d` > ? AND ( `fairies`.`e` = ? OR ( `fairies`.`f` = ? AND `fairies`.`g` = ? ) OR ( `fairies`.`h` = ? OR `fairies`.`i` = ? ) )  GROUP BY `fairies`.`id` HAVING `fairies`.`j` < korova OR `fairies`.`l` > ? AND ( `fairies`.`m` = ? OR ( `fairies`.`n` = ? AND `fairies`.`o` = ? ) )  ORDER BY `fairies`.`id` DESC LIMIT 5 OFFSET 6 ", current($query));
+	}
+
+	/**
+	 * @covers Query_Mysql_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQuerySelect2()
+	{
+		$query = $this->object
+			->table('fairies')
+			->where('a', 7)
+			->join('test', array('fairies.test_id', 'test.id'))
+			->join('test2', array(
+				array('fairies.test2_id', 'test.test_id'),
+				array('fairies.test3_id', 'test.id')
+				), 'inner')
+			->order_by('id', 'desc')
+			->query();
+		$this->assertEquals("SELECT * FROM `fairies` LEFT JOIN `test` ON `fairies`.`test_id` = `test`.`id` INNER JOIN `test2` ON ( `fairies`.`test2_id` = `test`.`test_id` AND `fairies`.`test3_id` = `test`.`id` ) WHERE `fairies`.`a` = ?  ORDER BY `fairies`.`id` DESC ", current($query));
+	}
+
+	/**
+	 * @covers Query_Mysql_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQueryDelete()
+	{
+		$query = $this->object
+			->type('delete')
+			->table('fairies')
+			->where('id', 1)
+			->query();
+
+		$this->assertEquals("DELETE fairies.* FROM `fairies` WHERE `fairies`.`id` = ?  ", current($query));
+	}
+
+	/**
+	 * @covers Query_Mysql_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQueryInsert()
+	{
+		$query = $this->object
+			->type('insert')
+			->table('fairies')
+			->data(array('id' => 1, 'name' => 'Trixie'))
+			->query();
+
+		$this->assertEquals("INSERT INTO `fairies` (`id`, `name`) VALUES(?, ?)", current($query));
+	}
+
+	/**
+	 * @covers Query_Mysql_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQueryUpdate()
+	{
+		$query = $this->object
+			->type('update')
+			->table('fairies')
+			->data(array('id' => 1, 'name' => 'Trixie'))
+			->query();
+
+		$this->assertEquals("UPDATE `fairies` SET `id` = ?, `name` = ? ", current($query));
+	}
+
+	/**
+	 * @covers Query_Mysql_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQueryCount()
+	{
+		$query = $this->object
+			->type('count')
+			->table('fairies')
+			->where('id', 8)
+			->query();
+
+		$this->assertEquals("SELECT COUNT(*) as `count` FROM `fairies` WHERE `fairies`.`id` = ?  ", current($query));
+	}
+
+	/**
+	 * @covers Query_Mysql_Driver::add_alias
+	 * @todo   Implement testQuery().
+	 */
+	public function testAlias()
+	{
+		$this->object->table('fairies');
+		$this->assertEquals('fairies', $this->object->last_alias());
+		$this->object->add_alias();
+		$this->assertEquals('a0', $this->object->last_alias());
+	}
+
+	/**
+	 * @covers Query_Mysql_Driver::__call
+	 * @todo   Implement testQuery().
+	 */
+	public function testCall()
+	{
+		$this->object->table('fairies');
+		$this->assertEquals('fairies', $this->object->table());
+		$except = false;
+		try {
+			$this->object->limit('fairies');
+		} catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true, $except);
+	}
+
+}

+ 132 - 0
php-phpixie/vendor/phpixie/db/tests/db/mysql/resultTest.php

@@ -0,0 +1,132 @@
+<?php
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-02-06 at 20:48:50.
+ */
+class Mysql_Result_Test extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Result_Mysql_Driver
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$stub = $this->getMockBuilder('mysqli_result')
+			->disableOriginalConstructor()
+			->getMock();
+		$stub->expects($this->any())
+			->method('fetch_object')
+			->will($this->onConsecutiveCalls(
+					(object) array('id' => 1, 'name' => 'Tinkerbell'), (object) array('id' => 2, 'name' => 'Trixie'), null
+		));
+
+		$this->object = new \PHPixie\DB\Mysql\Result($stub);
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+
+	}
+
+	/**
+	 * @covers Result_Mysql_Driver::rewind
+	 * @todo   Implement testRewind().
+	 */
+	public function testRewind()
+	{
+		$except = false;
+		$this->object->valid();
+		$this->object->rewind();
+		$this->object->next();
+		try {
+			$this->object->rewind();
+		} catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true, $except);
+	}
+
+	/**
+	 * @covers Result_Mysql_Driver::current
+	 */
+	public function testCurrent()
+	{
+		$this->assertEquals($this->object->current()->name, 'Tinkerbell');
+	}
+
+	/**
+	 * @covers Result_Mysql_Driver::valid
+	 */
+	public function testVaid()
+	{
+		$this->assertEquals($this->object->valid(), true);
+	}
+
+	/**
+	 * @covers Result_Mysql_Driver::key
+	 */
+	public function testKey()
+	{
+		$this->assertEquals($this->object->key(), 0);
+	}
+
+	/**
+	 * @covers Result_Mysql_Driver::key
+	 */
+	public function testGet()
+	{
+		$this->assertEquals($this->object->get('id'), 1);
+	}
+
+	/**
+	 * @covers Result_Mysql_Driver::as_array
+	 */
+	public function testAs_Array()
+	{
+		$arr = $this->object->as_array();
+		$this->assertArrayHasKey(0, $arr);
+		$this->assertArrayHasKey('name', (array) $arr[0]);
+		$this->assertEquals($arr[0]->name, 'Tinkerbell');
+		$this->assertArrayHasKey(1, $arr);
+		$this->assertArrayHasKey('id', (array) $arr[1]);
+		$this->assertEquals($arr[1]->id, 2);
+	}
+
+	public function testIterator()
+	{
+		$this->assertEquals($this->object->valid(), true);
+		$this->assertEquals($this->object->get('id'), 1);
+		foreach ($this->object as $key => $row)
+		{
+			if ($key == 0)
+			{
+				$this->assertEquals($row->name, 'Tinkerbell');
+				$this->assertEquals($row->id, 1);
+			}
+			if ($key == 1)
+			{
+				$this->assertEquals($row->name, 'Trixie');
+				$this->assertEquals(2, $this->object->get('id'));
+				$this->assertEquals($row->id, 2);
+			}
+		}
+		$this->assertEquals(false, $this->object->valid());
+		$this->assertEquals(null, $this->object->get('id'));
+		$this->assertEquals(null, $this->object->current());
+		$this->object->next();
+		$this->object->next();
+		$this->object->next();
+		$this->assertEquals(1, $this->object->key());
+	}
+
+}

+ 127 - 0
php-phpixie/vendor/phpixie/db/tests/db/pdo/connectionTest.php

@@ -0,0 +1,127 @@
+<?php
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator on 2013-02-07 at 12:41:50.
+ */
+class PDO_Connection_DriverTest extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var \PHPixie\DB\PDO\Connection
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$this->db_file = tempnam(sys_get_temp_dir(), 'test.sqlite');
+		$this->conf_file = tempnam(sys_get_temp_dir(), 'test.conf');
+		file_put_contents($this->db_file, '');
+		$db = new PDO('sqlite:'.$this->db_file);
+		$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+		$db->exec("CREATE TABLE fairies(id INT PRIMARY_KEY,name VARCHAR(255))");
+		$pixie = $this->getMock('\PHPixie\Pixie',array('find_file'));
+		$pixie->expects($this->any())
+                 ->method('find_file')
+                 ->will($this->returnValue($this->conf_file));
+		$pixie-> db = new \PHPixie\DB($pixie);
+		$pixie->config->set('db.default.connection', 'sqlite:'.$this->db_file);
+		$pixie->config->set('db.default.driver', 'pdo');
+		$this->object = new \PHPixie\DB\PDO\Connection($pixie, 'default');
+		$db = null;
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+		$this->object->conn = null;
+		unlink($this->db_file);
+		unlink($this->conf_file);
+	}
+
+	/**
+	 * @covers \PHPixie\DB\PDO\Connection::build_query
+	 * @todo   Implement testBuild_query().
+	 */
+	public function test_query()
+	{
+		$this->assertEquals('PHPixie\DB\PDO\Query',get_class($this->object->query('select')));
+	}
+
+	/**
+	 * @covers \PHPixie\DB\PDO\Connection::get_insert_id
+	 * @todo   Implement testGet_insert_id().
+	 */
+	public function testInsert_id()
+	{
+		$this->object->execute("INSERT INTO fairies(name)values('Trixie')");
+		$this->assertEquals(1, $this->object->insert_id());
+	}
+
+	/**
+	 * @covers \PHPixie\DB\PDO\Connection::list_columns
+	 * @todo   Implement testList_columns().
+	 */
+	public function testList_columns()
+	{
+		$cols = $this->object->list_columns('fairies');
+		$this->assertContains('id', $cols);
+		$this->assertContains('name', $cols);
+	}
+
+	/**
+	 * @covers \PHPixie\DB\PDO\Connection::execute
+	 * @todo   Implement testExecute().
+	 */
+	public function testExecute()
+	{
+		$this->object->execute("SELECT * FROM fairies where id = ?", array(1));
+	}
+
+	/**
+	 * @covers \PHPixie\DB\PDO\Connection::execute
+	 * @todo   Implement testExecute().
+	 */
+	public function testExecuteException()
+	{
+		$except = false;
+		try {
+			$this->object->execute("SELECUT * FROM fairies where id = ?", array(1));
+		} catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true, $except);
+	}
+
+	/**
+	 * @covers \PHPixie\DB\PDO\Connection::named_query
+	 * @todo   Implement testExecute().
+	 */
+	public function testNamed_query()
+	{
+		$this->object->named_query("SELECT * FROM fairies where id = :id", array(array('id' => 1)));
+	}
+
+	/**
+	 * @covers \PHPixie\DB\PDO\Connection::named_query
+	 * @todo   Implement testExecute().
+	 */
+	public function testNamed_queryException()
+	{
+		$except = false;
+		try {
+			$this->object->named_query("SELsECT * FROM fairies where id = :id", array(array('id' => 1)));
+		} catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true, $except);
+	}
+	
+
+}

+ 264 - 0
php-phpixie/vendor/phpixie/db/tests/db/pdo/queryTest.php

@@ -0,0 +1,264 @@
+<?php
+
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-02-01 at 06:23:13.
+ */
+class PDO_Query_Test extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Query_PDO_Driver
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$stub = (object) array('db_type' => 'mysql');
+		$this->object = new \PHPixie\DB\PDO\Query($stub, 'select');
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+
+	}
+
+	/**
+	 * @covers Query_PDO_Driver::escape_field
+	 * @todo   Implement testEscape_field().
+	 */
+	public function testEscape_field()
+	{
+		$this->object->add_alias();
+		$this->assertEquals('test', $this->object->escape_field(new \PHPixie\DB\Expression('test')));
+		$this->assertEquals('`a0`.*', $this->object->escape_field('*'));
+		$this->assertEquals('`a0`.`test`', $this->object->escape_field('test'));
+		$this->assertEquals('`test`.`test`', $this->object->escape_field('test.test'));
+	}
+
+	/**
+	 * @covers Query_PDO_Driver::escape_value
+	 * @todo   Implement testEscape_value().
+	 */
+	public function testEscape_value()
+	{
+		$params = array();
+		$this->assertEquals('test', $this->object->escape_value(new \PHPixie\DB\Expression('test'), $params));
+		$this->assertEquals('?', $this->object->escape_value('korova', $params));
+		$this->assertArrayHasKey(0, $params);
+		$this->assertEquals('korova', $params[0]);
+	}
+
+	/**
+	 * @covers Query_PDO_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQuerySelect1()
+	{
+		$query = $this->object
+			->table('fairies')
+			->where('a', 7)
+			->where('b', '<', 8)
+			->where('c', '>', 3)
+			->where('or', array('d', '>', 11))
+			->where(array(
+				array('e', 9),
+				array('or', array(
+						array('f', 10),
+						array('g', 11),
+					)),
+				array('or', array(
+						array('h', 12),
+						array('or', array('i', 13)),
+					))
+			))
+			->order_by('id', 'desc')
+			->group_by('id')
+			->having('j', '<', new \PHPixie\DB\Expression('korova'))
+			->having('or', array('l', '>', 11))
+			->having(array(
+				array('m', 9),
+				array('or', array(
+						array('n', 10),
+						array('o', 11),
+					))
+			))
+			->limit(5)
+			->offset(6)
+			->query();
+		$this->assertEquals("SELECT * FROM `fairies` WHERE `fairies`.`a` = ? AND `fairies`.`b` < ? AND `fairies`.`c` > ? OR `fairies`.`d` > ? AND ( `fairies`.`e` = ? OR ( `fairies`.`f` = ? AND `fairies`.`g` = ? ) OR ( `fairies`.`h` = ? OR `fairies`.`i` = ? ) )  GROUP BY `fairies`.`id` HAVING `fairies`.`j` < korova OR `fairies`.`l` > ? AND ( `fairies`.`m` = ? OR ( `fairies`.`n` = ? AND `fairies`.`o` = ? ) )  ORDER BY `fairies`.`id` DESC LIMIT 5 OFFSET 6 ", current($query));
+	}
+
+	/**
+	 * @covers Query_PDO_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQuerySelect2()
+	{
+		$query = $this->object
+			->table('fairies')
+			->where('a', 7)
+			->join('test', array('fairies.test_id', 'test.id'))
+			->join('test2', array(
+				array('fairies.test2_id', 'test.test_id'),
+				array('fairies.test3_id', 'test.id')
+				), 'inner')
+			->order_by('id', 'desc')
+			->query();
+		$this->assertEquals("SELECT * FROM `fairies` LEFT JOIN `test` ON `fairies`.`test_id` = `test`.`id` INNER JOIN `test2` ON ( `fairies`.`test2_id` = `test`.`test_id` AND `fairies`.`test3_id` = `test`.`id` ) WHERE `fairies`.`a` = ?  ORDER BY `fairies`.`id` DESC ", current($query));
+	}
+
+	/**
+	 * @covers Query_PDO_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQueryDelete()
+	{
+		$query = $this->object
+			->type('delete')
+			->table('fairies')
+			->where('id', 1)
+			->query();
+
+		$this->assertEquals("DELETE fairies.* FROM `fairies` WHERE `fairies`.`id` = ?  ", current($query));
+	}
+
+	/**
+	 * @covers Query_PDO_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQueryInsert()
+	{
+		$query = $this->object
+			->type('insert')
+			->table('fairies')
+			->data(array('id' => 1, 'name' => 'Trixie'))
+			->query();
+
+		$this->assertEquals("INSERT INTO `fairies` (`id`, `name`) VALUES(?, ?)", current($query));
+	}
+
+	/**
+	 * @covers Query_PDO_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQueryUpdate()
+	{
+		$query = $this->object
+			->type('update')
+			->table('fairies')
+			->data(array('id' => 1, 'name' => 'Trixie'))
+			->query();
+
+		$this->assertEquals("UPDATE `fairies` SET `id` = ?, `name` = ? ", current($query));
+	}
+
+	/**
+	 * @covers Query_PDO_Driver::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQueryCount()
+	{
+		$query = $this->object
+			->type('count')
+			->table('fairies')
+			->where('id', 8)
+			->query();
+
+		$this->assertEquals("SELECT COUNT(*) as `count` FROM `fairies` WHERE `fairies`.`id` = ?  ", current($query));
+	}
+
+	/**
+	 * @covers Query_PDO_Driver::add_alias
+	 * @todo   Implement testQuery().
+	 */
+	public function testAlias()
+	{
+		$this->object->table('fairies');
+		$this->assertEquals('fairies', $this->object->last_alias());
+		$this->object->add_alias();
+		$this->assertEquals('a0', $this->object->last_alias());
+	}
+
+	/**
+	 * @covers Query_PDO_Driver::__call
+	 * @todo   Implement testQuery().
+	 */
+	public function testCall()
+	{
+		$this->object->table('fairies');
+		$this->assertEquals('fairies', $this->object->table());
+		$except = false;
+		try {
+			$this->object->limit('fairies');
+		} catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true, $except);
+	}
+
+	public function testUnion()
+	{
+		$stub = (object) array('db_type' => 'mysql');
+		$subquery = new \PHPixie\DB\PDO\Query($stub, 'select');
+		$subquery->table('fairies');
+		$this->object->table('fairies');
+		$this->object->where('id', '>', 7);
+		$this->object->union($subquery);
+		$this->object->union($subquery);
+		$this->assertEquals('(SELECT * FROM `fairies` WHERE `fairies`.`id` > ?  ) UNION ALL (SELECT * FROM `fairies` ) UNION ALL (SELECT * FROM `fairies` ) ', current($this->object->query()));
+	}
+
+	public function testSubselect()
+	{
+		$stub = (object) array('db_type' => 'mysql');
+		$subquery = new \PHPixie\DB\PDO\Query($stub, 'select');
+		$subquery->fields('id')->table('fairies');
+		$this->object->table('fairies')->where('id', 7)->where('id', 'in', $subquery);
+		$this->assertEquals('SELECT * FROM `fairies` WHERE `fairies`.`id` = ? AND `fairies`.`id` in (SELECT `fairies`.`id` FROM `fairies` )   ', current($this->object->query()));
+	}
+
+	public function testSubtable()
+	{
+		$stub = (object) array('db_type' => 'mysql');
+		$subquery = new \PHPixie\DB\PDO\Query($stub, 'select');
+		$subquery->fields('id')->table('fairies');
+		$this->object->table($subquery)->where('id', 7);
+		$this->assertEquals('SELECT * FROM (SELECT `fairies`.`id` FROM `fairies` )  AS a0 WHERE `a0`.`id` = ?  ', current($this->object->query()));
+	}
+
+	public function testJoinSubtable()
+	{
+		$stub = (object) array('db_type' => 'mysql');
+		$subquery = new \PHPixie\DB\PDO\Query($stub, 'select');
+		$subquery->table('fairies');
+		$this->object->table($subquery);
+		$this->object->join('pixies', array('fairies.id', '=', 'pixie.id'));
+		$this->object->join(array('fairies', 'fae'), array('fairies.id', '=', 'fae.id'));
+		$this->object->join(array($subquery, 'fae2'), array('fairies.id', '=', 'fae2.id'));
+
+
+		$this->assertEquals('SELECT * FROM (SELECT * FROM `fairies` )  AS a0 LEFT JOIN `pixies` ON `fairies`.`id` = `pixie`.`id` LEFT JOIN `fairies` AS fae ON `fairies`.`id` = `fae`.`id` LEFT JOIN (SELECT * FROM `fairies` )  AS fae2 ON `fairies`.`id` = `fae2`.`id` ', current($this->object->query()));
+	}
+
+	public function testExpressionSelect()
+	{
+		$this->object->table('fairies')->where('id', 'in', new \PHPixie\DB\Expression("(SELECT id from fairies)"));
+		$this->assertEquals('SELECT * FROM `fairies` WHERE `fairies`.`id` in (SELECT id from fairies)  ', current($this->object->query()));
+	}
+	
+	public function testExpressionQuery()
+	{
+		$this->object->table('fairies')->where(new \PHPixie\DB\Expression('fairies.id'), 5);
+		$this->assertEquals('SELECT * FROM `fairies` WHERE fairies.id = ?  ', current($this->object->query()));
+	}
+
+}

+ 134 - 0
php-phpixie/vendor/phpixie/db/tests/db/pdo/resultTest.php

@@ -0,0 +1,134 @@
+<?php
+
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator 1.2.0 on 2013-02-06 at 20:48:50.
+ */
+class PDO_Result_Test extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Result_PDO_Driver
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$db = new PDO('sqlite::memory:');
+		$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+		$db->exec("CREATE TABLE fairies(id INT,name VARCHAR(255))");
+
+		$db->exec("INSERT INTO fairies (id,name) VALUES (1,'Tinkerbell')");
+		$db->exec("INSERT INTO fairies (id,name) VALUES (2,'Trixie')");
+
+		$q = $db->prepare("SELECT * from fairies");
+		$q->execute();
+
+		$this->object = new \PHPixie\DB\PDO\Result($q);
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+
+	}
+
+	/**
+	 * @covers Result_PDO_Driver::rewind
+	 * @todo   Implement testRewind().
+	 */
+	public function testRewind()
+	{
+		$except = false;
+		$this->object->valid();
+		$this->object->rewind();
+		$this->object->next();
+		try {
+			$this->object->rewind();
+		} catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true, $except);
+	}
+
+	/**
+	 * @covers Result_PDO_Driver::current
+	 */
+	public function testCurrent()
+	{
+		$this->assertEquals($this->object->current()->name, 'Tinkerbell');
+	}
+
+	/**
+	 * @covers Result_PDO_Driver::valid
+	 */
+	public function testVaid()
+	{
+		$this->assertEquals($this->object->valid(), true);
+	}
+
+	/**
+	 * @covers Result_PDO_Driver::key
+	 */
+	public function testKey()
+	{
+		$this->assertEquals($this->object->key(), 0);
+	}
+
+	/**
+	 * @covers Result_PDO_Driver::key
+	 */
+	public function testGet()
+	{
+		$this->assertEquals($this->object->get('id'), 1);
+	}
+
+	/**
+	 * @covers Result_PDO_Driver::as_array
+	 */
+	public function testAs_Array()
+	{
+		$arr = $this->object->as_array();
+		$this->assertArrayHasKey(0, $arr);
+		$this->assertArrayHasKey('name', (array) $arr[0]);
+		$this->assertEquals($arr[0]->name, 'Tinkerbell');
+		$this->assertArrayHasKey(1, $arr);
+		$this->assertArrayHasKey('id', (array) $arr[1]);
+		$this->assertEquals($arr[1]->id, 2);
+	}
+
+	public function testIterator()
+	{
+		$this->assertEquals($this->object->valid(), true);
+		$this->assertEquals($this->object->get('id'), 1);
+		foreach ($this->object as $key => $row)
+		{
+			if ($key == 0)
+			{
+				$this->assertEquals($row->name, 'Tinkerbell');
+				$this->assertEquals($row->id, 1);
+			}
+			if ($key == 1)
+			{
+				$this->assertEquals($row->name, 'Trixie');
+				$this->assertEquals(2, $this->object->get('id'));
+				$this->assertEquals($row->id, 2);
+			}
+		}
+		$this->assertEquals(false, $this->object->valid());
+		$this->assertEquals(null, $this->object->get('id'));
+		$this->assertEquals(null, $this->object->current());
+		$this->object->next();
+		$this->object->next();
+		$this->object->next();
+		$this->assertEquals(1, $this->object->key());
+	}
+
+}

+ 1 - 0
php-phpixie/vendor/phpixie/db/tests/phpunit.xml

@@ -0,0 +1 @@
+<phpunit bootstrap="bootstrap.php"></phpunit>

+ 4 - 0
php-phpixie/vendor/phpixie/orm/README.md

@@ -0,0 +1,4 @@
+PHPixie-ORM
+===========
+
+ORM Library for PHPixie

+ 79 - 0
php-phpixie/vendor/phpixie/orm/classes/PHPixie/ORM.php

@@ -0,0 +1,79 @@
+<?php
+
+namespace PHPixie;
+
+/**
+ * ORM Module for PHPixie
+ *
+ * This module allows you to instantly turn your tables 
+ * into Models and specify their relations in a simple way.
+ *
+ * @see \PHPixie\DB\Query
+ * @package    DB
+ */
+class ORM {
+	
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	public $pixie;
+	
+	/**
+	 * Cache of ORM tables columns
+	 * @var array
+	 */
+	public $column_cache = array();
+	
+	/**
+	 * Initializes the ORM module
+	 * 
+	 * @param \PHPixie\Pixie $pixie Pixie dependency container
+	 */
+	public function __construct($pixie) {
+		$this->pixie = $pixie;
+	}
+	
+	/**
+	 * Initializes ORM model by name, and optionally fetches an item by id
+	 *
+	 * @param string  $name Model name
+	 * @param mixed $id   If set ORM will try to load the item with this id from the database
+	 * @return \PHPixie\ORM\Model   ORM model, either empty or preloaded
+	 */
+	public function get($name, $id = null)
+	{
+		$model = $this->pixie->app_namespace."Model\\".ucfirst($name);
+		$model = new $model($this->pixie);
+		if ($id != null)
+		{
+			$model = $model->where($model->id_field, $id)->find();
+			$model->values(array($model->id_field => $id));
+		}
+		return $model;
+	}
+	
+	/**
+	 * Initializes an ORM Result with which model to use and which result to
+	 * iterate over
+	 *
+	 * @param string          $model  Model name
+	 * @param \PHPixie\DB\Result $dbresult Database result
+	 * @param array           $with Array of rules for preloaded relationships
+	 * @return \PHPixie\ORM\Result Initialized Result
+	 */
+	public function result($model, $dbresult, $with = array()) {
+		return new \PHPixie\ORM\Result($this->pixie, $model, $dbresult, $with);
+	}
+	
+	/**
+	 * Initializes an ORM Model Extension.
+	 *
+	 * @param string $class  Extension class name
+	 * @param \PHPixie\ORM\Model $model Associated Model
+	 * @return \PHPixie\ORM\Extension Initialized Extension
+	 */
+	public function extension($class, $model) {
+		return new $class($this->pixie, $model);
+	}
+}

+ 34 - 0
php-phpixie/vendor/phpixie/orm/classes/PHPixie/ORM/Extension.php

@@ -0,0 +1,34 @@
+<?php 
+namespace PHPixie\ORM;
+
+/**
+ * Abstract extension for the ORM Model.
+ * Actual extensions should extend this class.
+ *
+ * @package ORM
+ */
+abstract class Extension {
+
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	protected $pixie;
+	
+	/**
+	 * Associated ORM Model
+	 * @var \PHPixie\ORM\Model
+	 */
+	protected $model;
+	
+	/**
+	 * Initializes the extension.
+	 *
+	 * @param \PHPixie\Pixie $pixie Pixie dependency container
+	 */
+	public function __construct($pixie, $model) {
+		$this->pixie = $pixie;
+		$this->model = $model;
+	}
+	
+}

+ 290 - 0
php-phpixie/vendor/phpixie/orm/classes/PHPixie/ORM/Extension/Nested.php

@@ -0,0 +1,290 @@
+<?php
+namespace PHPixie\ORM\Extension;
+
+/**
+ * Nested sets support for the ORM Model
+ *
+ * @package ORM
+ */
+class Nested extends \PHPixie\ORM\Extension{
+	
+	/**
+	 * Method to modify each database query.
+	 * Useful if you need to add an additional special condition.
+	 *
+	 * @param \PHPixie\DB\Query $query Query to modify
+	 * @return \PHPixie\DB\Query Modified Query
+	 */
+	protected function modify_query($query) {
+		return $query;
+	}
+	
+	/**
+	 * Builds a query to get maximum rpos value.
+	 *
+	 * @return \PHPixie\DB\Query
+	 */
+	protected function max_rpos_query() {
+		return $this->modify_query(
+					$this->model->conn->query('select')
+						->fields($this->pixie->db->expr('MAX(rpos) as rpos'))
+						->table($this->model->table)
+				);
+	}
+	
+	/**
+	 * Builds a query to assign negative positions to child nodes.
+	 *
+	 * @return \PHPixie\DB\Query
+	 */
+	protected function reverse_children_pos_query() {
+		return $this->modify_query(
+					$this->model->conn->query('update')
+						->table($this->model->table)
+						->data(array(
+							'lpos' => $this->pixie->db->expr('0-lpos'),
+							'rpos' => $this->pixie->db->expr('0-rpos')
+						))
+						->where('lpos', '>', $this->model->lpos)
+						->where('rpos', '<', $this->model->rpos)
+				);
+	}
+	
+	/**
+	 * Builds a query to pad out rpos of nodes to the right of the insertion spot.
+	 *
+	 * @param int $lpos Lpos of insertion spot
+	 * @param int $width Pad width
+	 * @return \PHPixie\DB\Query
+	 */
+	protected function pad_rpos_query($lpos, $width) {
+		return $this->modify_query(
+					$this->model->conn->query('update')
+						->table($this->model->table)
+						->data(array(
+							'rpos' => $this->pixie->db->expr('rpos + '.$width)
+						))
+					->where('rpos', '>=', $lpos)
+				);
+	}
+	
+	/**
+	 * Builds a query to pad out lpos of nodes to the right of the insertion spot.
+	 *
+	 * @param int $lpos Lpos of insertion spot
+	 * @param int $width Pad width
+	 * @return \PHPixie\DB\Query
+	 */
+	protected function pad_lpos_query($lpos, $width) {
+		return $this->modify_query(
+					$this->model->conn->query('update')
+						->table($this->model->table)
+						->data(array(
+							'lpos' => $this->pixie->db->expr('lpos + '.$width)
+						))
+						->where('lpos', '>=', $lpos)
+				);
+	}
+	
+	/**
+	 * Builds a query to collapse rpos of nodes to the right of the current node.
+	 *
+	 * @param int $width Collapse width
+	 * @param bool $collapse_self Whether to collapse the rpos of the current node too.
+	 * @return \PHPixie\DB\Query
+	 */
+	protected function collapse_rpos_query($width, $collapse_self = false) {
+		return $this->modify_query(
+					$this->model->conn->query('update')
+						->table($this->model->table)
+						->data(array(
+							'rpos' => $this->pixie->db->expr('rpos - '.($width))
+						))
+						->where('rpos', $collapse_self?'>=':'>', $this->model->rpos)
+				);
+	}
+	
+	/**
+	 * Builds a query to collapse lpos of nodes to the right of the current node.
+	 *
+	 * @param int $width Collapse width
+	 * @return \PHPixie\DB\Query
+	 */
+	protected function collapse_lpos_query($width) {
+		return $this->modify_query(
+					$this->model->conn->query('update')
+						->table($this->model->table)
+						->data(array(
+							'lpos' => $this->pixie->db->expr('lpos - '.($width))
+						))
+						->where('lpos', '>', $this->model->rpos)
+				);
+	}
+	
+	/**
+	 * Builds a query to put nodes with negative positions to their proper spots.
+	 *
+	 * @param int $pos_offset Offset by which to move the positions
+	 * @param int $depth_offset Offset by which to modify depths
+	 * @return \PHPixie\DB\Query
+	 */
+	protected function update_reversed_query($pos_offset, $depth_offset) {
+		return $this->modify_query(
+					$this->model->conn->query('update')
+						->table($this->model->table)
+						->data(array(
+							'lpos' => $this->pixie->db->expr("0 - lpos + $pos_offset"),
+							'rpos' => $this->pixie-> db->expr("0 - rpos + $pos_offset"),
+							'depth' => $this->pixie->db->expr("depth + $depth_offset")
+						))
+					->where('rpos', '<', 0)
+				);
+	}
+	
+	/**
+	 * Builds a query to delete children of the current node.
+	 *
+	 * @return \PHPixie\DB\Query
+	 */
+	protected function delete_children_query() {
+		return $this->modify_query(
+				$this->model->conn->query('delete')
+					->table($this->model->table)
+					->where('lpos', '>', $this->model->lpos)
+					->where('rpos', '<', $this->model->rpos)
+			);
+	}
+	
+	/**
+	 * Calculates the width of the current node.
+	 *
+	 * @return int
+	 */
+	protected function width() {
+		return $this->model->loaded()?$this->model->rpos - $this->model->lpos + 1:2;
+	}
+	
+	/**
+	 * Move current node to a new position in the tree.
+	 * 
+	 * @param \PHPixie\ORM\Model $parent Parent to append the node to.
+	 * @param bool $append_to_beginning  Prepend node to the beginning of children list.
+	 * @param bool $children_only Whether to move children of the node instead of the whole node.
+	 *                            Defaults to false.
+	 * @return void
+	 */
+	protected function move_to($parent, $append_to_beginning = false, $children_only = false) {
+		$width = $this->width();
+		if ($children_only) {
+			$width = $width - 2;
+		}
+		if ($parent != null) {
+			$lpos = $append_to_beginning?$parent->lpos+1:$parent->rpos;
+			$depth = $parent->depth + 1;
+		}else{
+			$lpos = ($append_to_beginning?0:$this->max_rpos_query()->execute()->current()->rpos) + 1;
+			$depth = 0;
+		}
+		$rpos = $lpos + $width - 1;
+		
+		if ($this->model->loaded() && $width>2)
+			$this->reverse_children_pos_query()->execute();
+			
+		$this->pad_rpos_query($lpos, $width)->execute();
+		$this->pad_lpos_query($lpos, $width)->execute();
+		
+		if($this->model->loaded()){
+			$this->collapse_rpos_query($width, $children_only)->execute();
+			$this->collapse_lpos_query($width)->execute();
+			$depth_offset = $depth - $this->model->depth;
+			
+			if ($lpos > $this->model->lpos){
+				$lpos = $lpos - $width;
+				$rpos = $rpos - $width;
+			}
+			
+			$pos_offset = $lpos - $this->model->lpos;
+			if ($children_only) {
+				$pos_offset = $pos_offset - 1;
+				$depth_offset = $depth_offset - 1;
+			}
+			$this->update_reversed_query($pos_offset, $depth_offset)->execute();
+		}
+		
+		if (!$children_only) {
+			$this->model->lpos = $lpos;
+			$this->model->depth = $depth;
+			$this->model->rpos = $rpos;
+		}else {
+			if ($lpos < $this->model->lpos)
+				$this->model->lpos = $this->model->lpos + $width;
+			$this->model->rpos = $this->model->lpos + 1;
+		}
+	}
+	
+	/**
+	 * Prepare the tree for the node move. 
+	 * Execute save() on the model afterwards.
+	 * 
+	 * @param \PHPixie\ORM\Model $parent Parent to append the node to.
+	 * @param bool $append_to_beginning  Prepend node to the beginning of children list.
+	 *
+	 * @return \PHPixie\ORM\Model Current Model
+	 */
+	public function prepare_append($parent = null, $append_to_beginning = false){
+		$this->move_to($parent, $append_to_beginning);
+		return $this->model;
+	}
+	
+	/**
+	 * Move children of the current node to the new parent.
+	 * 
+	 * @param \PHPixie\ORM\Model $parent Parent to move child nodes to.
+	 * @param bool $append_to_beginning  Prepend node to the beginning of children list.
+	 *
+	 * @return \PHPixie\ORM\Model Current Model
+	 * @throw \Exception If associated model is not loaded
+	 */
+	public function move_children($parent = null, $append_to_beginning = false) {
+		if (!$this->model->loaded())
+			throw new \Exception("The model is not loaded, hence has no children.");
+		if($this->width()>2)
+			$this->move_to($parent, $append_to_beginning, true);
+		return $this->model;
+	}
+	
+	/**
+	 * Prepare tree for deletion of the current node.
+	 * Call delete() on the model afterwards.
+	 * 
+	 * @return \PHPixie\ORM\Model Current Model
+	 * @throw \Exception If associated model is not loaded
+	 */
+	public function prepare_delete() {
+		if (!$this->model->loaded())
+			throw new \Exception("The model is not loaded");
+		$width = $this->width();
+		if($width>2)
+			$this->delete_children_query()->execute();
+		$this->collapse_rpos_query($width)->execute();
+		$this->collapse_lpos_query($width)->execute();
+		return $this->model;
+	}
+	
+	/**
+	 * ORM Model with conditions set so that you can get the children
+	 * of the current node.
+	 * 
+	 * @return \PHPixie\ORM\Model Model with conditions set
+	 * @throw \Exception If associated model is not loaded
+	 */
+	public function children() {
+		if (!$this->model->loaded())
+			throw new \Exception("The model is not loaded");
+		return $this->pixie->orm->get($this->model->model_name)
+				->where('lpos', '>', $this->model->lpos)
+				->where('rpos', '<', $this->model->rpos)
+				->order_by('lpos', 'asc');
+	}
+	
+}

+ 846 - 0
php-phpixie/vendor/phpixie/orm/classes/PHPixie/ORM/Model.php

@@ -0,0 +1,846 @@
+<?php
+
+namespace PHPixie\ORM;
+
+/**
+ * ORM allows you to access database items and their relationships in an OOP manner,
+ * it is easy to setup and makes a lot of use of naming convention.
+ *
+ * @method mixed limit(int $limit = null) Set number of rows to return.
+ *               If NULL is passed than no limit is used.
+ *               Without arguments returns current limit, returns self otherwise.
+ *
+ * @method mixed offset(int $offset = null) Set the offset for the first row in result.
+ *               If NULL is passed than no limit is used.
+ *               Without arguments returns current offset, returns self otherwise.
+ *
+ * @method mixed order_by(string $column, string $dir) Adds a column to ordering parameters
+ *
+ * @method mixed where(mixed $key, mixed $operator = null, mixed $val = null) behaves just like Query_Database::where()
+ *
+ * @see Query_Database::where()
+ * @package ORM
+ */
+class Model
+{
+
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	public $pixie;
+
+	/**
+	 * Database Connection
+	 * @var \PHPixie\DB\Connection
+	 */
+	public $conn;
+	
+	/**
+	 * Specifies which table the model will use, can be overridden
+	 * @var string
+	 */
+	public $table = null;
+
+	/**
+	 * Specifies which connection the model will use, can be overridden
+	 * but a model can have relationships only with models utilizing the same connection
+	 * @var string
+	 */
+	public $connection = 'default';
+
+	/**
+	 * Specifies which column is treated as PRIMARY KEY
+	 * @var string
+	 */
+	public $id_field = 'id';
+
+	/**
+	 * You can define 'Belongs to' relationships buy changing this array
+	 * @var array
+	 */
+	protected $belongs_to = array();
+
+	/**
+	 * You can define 'Has one' relationships buy changing this array
+	 * @var array
+	 */
+	protected $has_one = array();
+
+	/**
+	 * You can define 'Has many' relationships buy changing this array
+	 * @var array
+	 */
+	protected $has_many = array();
+
+	/**
+	 * Associated query builder
+	 * @var \PHPixie\DB\Query
+	 */
+	public $query;
+
+	/**
+	 * The name of the model
+	 * @var string
+	 */
+	public $model_name;
+
+	/**
+	 * Cached properties
+	 * @var array
+	 */
+	public $cached = array();
+
+	/**
+	 * An instance of the database connection
+	 * @var DB
+	 */
+	protected $db;
+
+	/**
+	 * Current row returned by the database
+	 * @var array
+	 */
+	protected $_row = array();
+
+	/**
+	 * A flag whether the row was loaded from the database
+	 * @var boolean
+	 */
+	protected $_loaded = false;
+
+	/**
+	 * Relationships to be preloaded
+	 * @var array
+	 */
+	protected $_with = array();
+	
+	/**
+	 * Extension definitions
+	 * @var array
+	 */
+	protected $extensions = array();
+	
+	/**
+	 * Extension instances
+	 * @var array
+	 */
+	protected $extension_instances = array();
+	
+	/**
+	 * Cached column names for tables
+	 * @var array
+	 */
+	protected static $_column_cache = array();
+
+	/**
+	 * Constructs the model. To use ORM it is enough to
+	 * just create a model like this:
+	 * <code>
+	 * class App\Model\Fairy extends \PHPixie\ORM\Model { }
+	 * </code>
+	 * By default it will assume that the name of your table
+	 * is the plural form of the models' name, the PRIMARY KEY is id,
+	 * and will use the 'default' connection. This behaviour is easy to be
+	 * changed by overriding $table, $id and $db properties.
+	 *
+	 * @param \PHPixie\Pixie $pixie Pixie dependency container
+	 * @return void
+	 * @see $table
+	 * @see $id
+	 * @see $db
+	 */
+	public function __construct($pixie)
+	{
+		$this->pixie = $pixie;
+		$this->conn = $pixie->db->get($this->connection);
+		$this->query = $this->conn->query('select');
+		$this->model_name = strtolower(get_class($this));
+		$this->model_name = str_ireplace($this->pixie->app_namespace."Model\\", '', $this->model_name);
+		
+		if ($this->table == null)
+		{
+			$this->table = str_replace("\\", '_', $this->model_name);
+			$this->table = $this->plural($this->table);
+		}
+		$this->query->table($this->table);
+
+		foreach (array('belongs_to', 'has_one', 'has_many') as $rels)
+		{
+			$normalized = array();
+			foreach ($this->$rels as $key => $rel)
+			{
+				if (!is_array($rel))
+				{
+					$key = $rel;
+					$rel = array();
+				}
+				$normalized[$key] = $rel;
+				if (!isset($rel['model']))
+				{
+					$rel['model'] = $normalized[$key]['model'] = $rels == 'has_many' ? $this->singular($key) : $key;
+				}
+
+				$normalized[$key]['type'] = $rels;
+				if (!isset($rel['key']))
+				{
+					$normalized[$key]['key'] = $this->model_key( $rels != 'belongs_to' ? $this->model_name : $rel['model']);
+				}
+
+				if ($rels == 'has_many' && isset($rel['through']))
+				{
+					if (!isset($rel['foreign_key']))
+					{
+						$normalized[$key]['foreign_key'] = $this->model_key($rel['model']);
+					}
+				}
+
+				$normalized[$key]['name'] = $key;
+			}
+			$this->$rels = $normalized;
+		}
+	}
+	
+	/**
+	 * Get model foreign key from model name
+	 *
+	 * @param string $model_name      Name of the model
+	 *
+	 * @return string  Foreign key for specified model name.
+	 */
+	public function model_key($model_name) {
+		return str_replace("\\", '_', $model_name).'_id';
+	}
+	
+	/**
+	 * Magic method for call Query_Database methods
+	 *
+	 * @param string $method      Method to call
+	 * @param array $arguments Arguments passed to the method
+	 * @return mixed  Returns self if parameters were passed. If no parameters where passed returns
+	 *                current value for the associated parameter
+	 * @throws \Exception If method doesn't exist
+	 */
+	public function __call($method, $arguments)
+	{
+		if (!in_array($method, array('limit', 'offset', 'order_by', 'where')))
+		{
+			throw new \Exception("Method '{$method}' doesn't exist on .".get_class($this));
+		}
+		$res = call_user_func_array(array($this->query, $method), $arguments);
+		if (empty($arguments))
+			return $res;
+		
+		return $this;
+	}
+	
+	/**
+	 * Prepares the relationships specified using with().
+	 *
+	 * @return array Relationship definitions used by \PHPixie\ORM\Result
+	 * @throw  \Exception If the relationship specified using with() does not exist or is not of the belongs_to or has_one type
+	 */
+	public function prepare_relations() {
+		$paths = array();
+		if (!empty($this->_with))
+		{
+			$fields = array();
+			$this_alias = $this->query->last_alias();
+			foreach ($this->columns() as $column)
+			{
+				$fields[] = array("{$this_alias}.{$column}", "{$this_alias}__{$column}");
+			}
+			foreach ($this->_with as $target)
+			{
+				$model = $this;
+				$model_alias = $this_alias;
+				$rels = explode('.', $target);
+				foreach ($rels as $key => $rel_name)
+				{
+					$path = implode('.', array_slice($rels, 0, $key + 1));
+					if (isset($paths[$path]))
+					{
+						$model = $paths[$path]['model'];
+						$model_alias = $paths[$path]['alias'];
+						continue;
+					}
+					$alias = $this->query->add_alias();
+					$model_rels = array_merge($model->has_one, $model->has_many, $model->belongs_to);
+					$rel = $this->pixie->arr($model_rels, $rel_name, false);
+
+					if (!$rel)
+					{
+						throw new \Exception("Model '{$model->model_name}' doesn't have a '{$rel_name}' relation defined");
+					}
+					if ($rel['type'] == 'has_many')
+					{
+						throw new \Exception("Relationship '{$rel_name}' is of has_many type and cannot be preloaded view with()");
+					}
+					$rel_model = $this->pixie->orm->get($rel['model']);
+
+					if ($rel['type'] == 'belongs_to')
+					{
+						$this->query->join(array($rel_model->table, $alias), array(
+							$model_alias.'.'.$rel['key'],
+							$alias.'.'.$rel_model->id_field,
+							), 'left');
+					}
+					else
+					{
+						$this->query->join(array($rel_model->table, $alias), array(
+							$model_alias.'.'.$model->id_field,
+							$alias.'.'.$rel['key'],
+							), 'left');
+					}
+
+					foreach ($rel_model->columns() as $column)
+					{
+						$fields[] = array("{$alias}.{$column}", "{$alias}__{$column}");
+					}
+					$model = $rel_model;
+					$model_alias = $alias;
+					$paths[$path] = array('alias' => $alias, 'model' => $model);
+				}
+			}
+
+			call_user_func_array(array($this->query, 'fields'), $fields);
+		}
+		
+		return $paths;
+		
+	}
+	
+	/**
+	 * Finds all rows that meet set criteria.
+	 *
+	 * @return \PHPixie\ORM\Result Returns ORM Result that you can use in a 'foreach' loop.
+	 */
+	public function find_all()
+	{
+		$paths = $this->prepare_relations();
+		return $this->pixie->orm->result($this->model_name, $this->query->execute(), $paths);
+	}
+
+	/**
+	 * Searches for the first row that meets set criteria. If no rows match it still returns an ORM model
+	 * but with its loaded() flag being False. calling save() on such an object will insert a new row.
+	 *
+	 * @return \PHPixie\ORM\Model Found item or new object of the current model but with loaded() flag being False
+	 */
+	public function find()
+	{
+		$set_limit = $this->limit();
+		$res = $this->limit(1)->find_all()->current();
+		$this->limit($set_limit);
+		return $res;
+	}
+
+	/**
+	 * Counts all rows that meet set criteria. Ignores limit and offset.
+	 *
+	 * @return int Number of rows
+	 */
+	public function count_all()
+	{
+		$query = clone $this->query;
+		$query->type('count');
+		return $query->execute();
+	}
+
+	/**
+	 * Checks if the item is considered to be loaded from the database
+	 *
+	 * @return boolean Returns True if the item was loaded
+	 */
+	public function loaded()
+	{
+		return $this->_loaded;
+	}
+
+	/**
+	 * Returns the row associated with current ORM item as an associative array
+	 *
+	 * @return array  Associative array representing the row
+	 */
+	public function as_array()
+	{
+		return $this->_row;
+	}
+
+	/**
+	 * Returns a clone of  query builder that is being used to set conditions.
+	 * It is useful for example if you let ORM manage building a complex query using it's relationship
+	 * system, then you get the clone of that query and alter it to your liking,
+	 * so there is no need to writing relationship joins yourself.
+	 *
+	 * @return \PHPixie\DB\Query A clone of the current query builder
+	 */
+	public function query()
+	{
+		return clone $this->query;
+	}
+
+	/**
+	 * You can override this method to return additional properties that you would like to use
+	 * in your model. One advantage for using this instead of just overriding __get() is that
+	 * in this way the properties also get cached.
+	 *
+	 * @param string $property The name of the property to get
+	 * @return void
+	 */
+	public function get($property)
+	{
+
+	}
+
+	/**
+	 * Magic method that allows to chech if the propert exists on the model.
+	 * Takes relationships and properties defined using get() into account.
+	 * @param string   $column Name of the column, property or relationship to get
+	 * @return boolean If the property exists
+	 */
+	public function __isset($property) {
+		if (array_key_exists($property, $this->_row))
+			return true;
+		if (array_key_exists($property, $this->cached))
+			return true;
+		if (($val = $this->get($property)) !== null)
+			return true;
+		$relations = array_merge($this->has_one, $this->has_many, $this->belongs_to);
+		if ($target = $this->pixie->arr($relations, $property, false))
+			return true;
+		return false;		
+	}
+	
+	/**
+	 * Magic method that allows accessing row columns and extensions as properties and also facilitates
+	 * access to relationships and custom properties defined in get() method.
+	 * If a relationship is being accessed, it will return an ORM model of the related table
+	 * and automatically alter its query so that all your previously set conditions will remain
+
+	 * @param string   $column Name of the column, property or relationship to get
+	 * @return mixed   Requested property
+	 * @throws \Exception If neither property nor a relationship with such name is found
+	 */
+	public function __get($column)
+	{
+		if (array_key_exists($column, $this->_row))
+			return $this->_row[$column];
+			
+		if (array_key_exists($column, $this->cached))
+			return $this->cached[$column];
+			
+		if (($val = $this->get($column)) !== null)
+		{
+			$this->cached[$column] = $val;
+			return $val;
+		}
+		
+		if (array_key_exists($column, $this->extension_instances))
+		{
+			return $this->extension_instances[$column];
+		}
+		
+		if (array_key_exists($column, $this->extensions))
+		{	
+			return $this->extension_instances[$column] = 
+				$this->pixie->orm->extension($this->extensions[$column], $this);
+		}
+		
+		$relations = array_merge($this->has_one, $this->has_many, $this->belongs_to);
+		if ($target = $this->pixie->arr($relations, $column, false))
+		{
+			$model = $this->pixie->orm->get($target['model']);
+			$model->query = clone $this->query;
+			if ($this->loaded())
+			{
+				$model->query->where($this->id_field, $this->_row[$this->id_field]);
+			}
+			if ($target['type'] == 'has_many' && isset($target['through']))
+			{
+				$last_alias = $model->query->last_alias();
+				$through_alias = $model->query->add_alias();
+				$new_alias = $model->query->add_alias();
+				$model->query->join(array($target['through'], $through_alias), array(
+					$last_alias.'.'.$this->id_field,
+					$through_alias.'.'.$target['key'],
+					), 'inner');
+				$model->query->join(array($model->table, $new_alias), array(
+					$through_alias.'.'.$target['foreign_key'],
+					$new_alias.'.'.$model->id_field,
+					), 'inner');
+			}
+			else
+			{
+				$last_alias = $model->query->last_alias();
+				$new_alias = $model->query->add_alias();
+				if ($target['type'] == 'belongs_to')
+				{
+					$model->query->join(array($model->table, $new_alias), array(
+						$last_alias.'.'.$target['key'],
+						$new_alias.'.'.$model->id_field,
+						), 'inner');
+				}
+				else
+				{
+					$model->query->join(array($model->table, $new_alias), array(
+						$last_alias.'.'.$this->id_field,
+						$new_alias.'.'.$target['key'],
+						), 'inner');
+				}
+			}
+			$model->query->fields("$new_alias.*");
+			if ($target['type'] != 'has_many' && $this->loaded())
+			{
+				$model = $model->find();
+				$this->cached[$column] = $model;
+			}
+			return $model;
+		}
+
+		throw new \Exception("Property {$column} not found on {$this->model_name} model.");
+	}
+
+	/**
+	 * Magic method to update record values when set as properties or to add an ORM item to
+	 * a relation. By assigning an ORM model to a relationship a relationship is created between the
+	 * current item and the passed one  Using properties this way is a shortcut to the add() method.
+	 *
+	 * @param string $column Column or relationship name
+	 * @param mixed $val    Column value or an ORM model to be added to a relation
+	 * @return void
+	 * @see add()
+	 */
+	public function __set($column, $val)
+	{
+		$relations = array_merge($this->has_one, $this->has_many, $this->belongs_to);
+		if (array_key_exists($column, $relations))
+		{
+			$this->add($column, $val);
+		}
+		else
+		{
+			$this->_row[$column] = $val;
+		}
+		$this->cached = array();
+	}
+
+	/**
+	 * Create a relationship between current item and an other one
+	 *
+	 * @param string   $relation Name of the relationship
+	 * @param \PHPixie\ORM\Model    $model    ORM item to create a relationship with
+	 * @return void
+	 * @throws \Exception If relationship is not defined
+	 * @throws \Exception If current item is not in the database yet (isn't considered loaded())
+	 * @throws \Exception If passed item is not in the database yet (isn't considered loaded())
+	 */
+	public function add($relation, $model)
+	{
+
+		$rels = array_merge($this->has_one, $this->has_many, $this->belongs_to);
+		$rel = $this->pixie->arr($rels, $relation, false);
+		if (!$rel)
+		{
+			throw new \Exception("Model doesn't have a '{$relation}' relation defined");
+		}
+
+		if ($rel['type'] == 'belongs_to')
+		{
+
+			if (!$model->loaded())
+			{
+				throw new \Exception("Model must be loaded before added to a belongs_to relationship. Probably you haven't saved it.");
+			}
+
+			$key = $rel['key'];
+			$this->$key = $model->_row[$this->id_field];
+			if ($this->loaded())
+			{
+				$this->save();
+			}
+		}
+		elseif (isset($rel['through']))
+		{
+
+			if (!$this->loaded())
+			{
+				throw new \Exception("Model must be loaded before you try adding 'through' relationships to it. Probably you haven't saved it.");
+			}
+			if (!$model->loaded())
+			{
+				throw new \Exception("Model must be loaded before added to a 'through' relationship. Probably you haven't saved it.");
+			}
+
+			$exists = $this->conn->query('count')
+				->table($rel['through'])
+				->where(array(
+					array($rel['key'], $this->_row[$this->id_field]),
+					array($rel['foreign_key'], $model->_row[$model->id_field])
+				))
+				->execute();
+			if (!$exists)
+			{
+				$this->conn->query('insert')
+					->table($rel['through'])
+					->data(array(
+						$rel['key'] => $this->_row[$this->id_field],
+						$rel['foreign_key'] => $model->_row[$model->id_field]
+					))
+					->execute();
+			}
+		}
+		else
+		{
+
+			if (!$this->loaded())
+			{
+				throw new \Exception("Model must be loaded before you try adding 'has_many' relationships to it. Probably you haven't saved it.");
+			}
+
+			$key = $rel['key'];
+			$model->$key = $this->_row[$this->id_field];
+			if ($model->loaded())
+			{
+				$model->save();
+			}
+		}
+		$this->cached = array();
+	}
+
+	/**
+	 * Removes a relationship between current item and the passed one
+	 *
+	 * @param string   $relation Name of the relationship
+	 * @param \PHPixie\ORM\Model    $model    ORM item to remove relationship with. Can be omitted for 'belongs_to' relationships
+	 * @return void
+	 * @throws \Exception If realtionship is not defined
+	 * @throws \Exception If current item is not in the database yet (isn't considered loaded())
+	 * @throws \Exception If passed item is not in the database yet (isn't considered loaded())
+	 */
+	public function remove($relation, $model = null)
+	{
+
+		if (!$this->loaded())
+		{
+			throw new \Exception("Model must be loaded before you try removing relationships from it.");
+		}
+
+		$rels = array_merge($this->has_one, $this->has_many, $this->belongs_to);
+		$rel = $this->pixie->arr($rels, $relation, false);
+		if (!$rel)
+		{
+			throw new \Exception("Model doesn't have a '{$relation}' relation defined");
+		}
+
+		if ($rel['type'] != 'belongs_to' && (!$model || !$model->loaded()))
+		{
+			throw new \Exception("Model must be loaded before being removed from a has_one or has_many relationship.");
+		}
+		if ($rel['type'] == 'belongs_to')
+		{
+			$key = $rel['key'];
+			$this->$key = null;
+			$this->save();
+		}
+		elseif (isset($rel['through']))
+		{
+			$this->conn->query('delete')
+				->table($rel['through'])
+				->where(array(
+					array($rel['key'], $this->_row[$this->id_field]),
+					array($rel['foreign_key'], $model->_row[$model->id_field])
+				))
+				->execute();
+		}
+		else
+		{
+			$key = $rel['key'];
+			$model->$key = null;
+			$model->save();
+		}
+		$this->cached = array();
+	}
+
+	/**
+	 * Gets name column names of the table associated with the model.
+	 *
+	 * @return array   Array of column names
+	 */
+	public function columns()
+	{
+		$cache = &$this->pixie->orm->column_cache;
+		
+		if (!isset($cache[$this->table]))
+			$cache[$this->table] = $this->conn->list_columns($this->table);
+		return $cache[$this->table];
+	}
+
+	/**
+	 * Gets the items id field value
+	 *
+	 * @return mixed   Item id
+	 */
+	public function id() 
+	{
+		if ($this->loaded())
+			return $this->_row[$this->id_field];
+			
+		return null;
+	}
+	
+	/**
+	 * Defines which relationships should be preloaded. You can only preload
+	 * belongs_to and has_one relationships. You can use the dot notation to
+	 * preload deep relationsips, e.g. 'tree.protector' will preload the tree
+	 * that a fairy lives in and also preload the protector of that tree.
+	 *
+	 * @param string $relationsip,...   List of relationships to preload
+	 * @return \PHPixie\ORM\Model Returns itself
+	 */
+	public function with()
+	{
+		$this->_with = func_get_args();
+		return $this;
+	}
+
+	/**
+	 * Deletes current item from the database
+	 *
+	 * @return void
+	 * @throws \Exception If the item is not in the database, e.g. is not loaded()
+	 */
+	public function delete()
+	{
+		if (!$this->loaded())
+		{
+			throw new \Exception("Cannot delete an item that wasn't selected from database");
+		}
+		$this->conn->query('delete')
+			->table($this->table)
+			->where($this->id_field, $this->_row[$this->id_field])
+			->execute();
+		$this->cached = array();
+	}
+
+	/**
+	 * Deletes all items that meet set conditions. Use in the same way
+	 * as you would a find_all() method.
+	 *
+	 * @return \PHPixie\ORM\Model Returns self
+	 */
+	public function delete_all()
+	{
+		$query = clone $this->query;
+		$query->type('delete');
+		$query->execute();
+		return $this;
+	}
+
+	/**
+	 * Saves the item back to the database. If item is loaded() it will result
+	 * in an update, otherwise a new row will be inserted
+	 *
+	 * @return \PHPixie\ORM\Model Returns self
+	 */
+	public function save()
+	{
+		if ($this->loaded())
+		{
+			$query = $this->conn->query('update')
+				->table($this->table)
+				->where($this->id_field, $this->_row[$this->id_field]);
+		}
+		else
+		{
+			$query = $this->conn->query('insert')
+				->table($this->table);
+		}
+		$query->data($this->_row);
+		$query->execute();
+
+		if ($this->loaded())
+		{
+			$id = $this->_row[$this->id_field];
+		}
+		else
+		{
+			$id = $this->conn->insert_id();
+		}
+		$row = (array) $this->conn->query('select')
+				->table($this->table)
+				->where($this->id_field, $id)->execute()->current();
+		$this->values($row, true);
+		return $this;
+	}
+
+	/**
+	 * Batch updates item columns using an associative array
+	 *
+	 * @param array $row        Associative array of key => value pairs
+	 * @param boolean $set_loaded Flag to consider the ORM item loaded. Useful if you selected
+	 *                            the row from the database and want to wrap it in ORM
+	 * @return \PHPixie\ORM\Model Returns self
+	 */
+	public function values($row, $set_loaded = false)
+	{
+		$this->_row = array_merge($this->_row, $row);
+		if ($set_loaded)
+		{
+			$this->_loaded = true;
+		}
+		$this->cached = array();
+		return $this;
+	}
+
+	/**
+	 * Gets plural form of a noun
+	 *
+	 * @param string  $str Noun to get a plural form of
+	 * @return string  Plural form
+	 */
+	protected function plural($str)
+	{
+		$regexes = array(
+			'/^(.*?[sxz])$/i' => '\\1es',
+			'/^(.*?[^aeioudgkprt]h)$/i' => '\\1es',
+			'/^(.*?[^aeiou])y$/i' => '\\1ies',
+		);
+		foreach ($regexes as $key => $val)
+		{
+			$str = preg_replace($key, $val, $str, -1, $count);
+			if ($count)
+			{
+				return $str;
+			}
+		}
+		return $str.'s';
+	}
+
+	/**
+	 * Gets singular form of a noun
+	 *
+	 * @param string $str Noun to get singular form of
+	 * @return string Singular form of the noun
+	 */
+	protected function singular($str)
+	{
+		$regexes = array(
+			'/^(.*?us)$/i' => '\\1',
+			'/^(.*?[sxz])es$/i' => '\\1',
+			'/^(.*?[^aeioudgkprt]h)es$/i' => '\\1',
+			'/^(.*?[^aeiou])ies$/i' => '\\1y',
+			'/^(.*?)s$/' => '\\1',
+		);
+		foreach ($regexes as $key => $val)
+		{
+			$str = preg_replace($key, $val, $str, -1, $count);
+			if ($count)
+			{
+				return $str;
+			}
+		}
+		return $str;
+	}
+
+}

+ 236 - 0
php-phpixie/vendor/phpixie/orm/classes/PHPixie/ORM/Result.php

@@ -0,0 +1,236 @@
+<?php
+
+namespace PHPixie\ORM;
+
+/**
+ * Allows iterating over ORM objects inside loops lie 'foreach',
+ * while preserving performance by working with only a single row
+ * at a time. It wraps conveniently wraps around Database_Result class
+ * returning ORM object instead of just data object.
+ *
+ * @see \PHPixie\Database\Result
+ * @package ORM
+ */
+class Result implements \Iterator
+{
+
+	/**
+	 * Pixie Dependancy Container
+	 * @var \PHPixie\Pixie
+	 */
+	public $pixie;
+	
+	/**
+	 * Name of the model that the rows belong to
+	 * @var string
+	 */
+	protected $_model;
+
+	/**
+	 * Database result
+	 * @var Result_Database
+	 */
+	protected $_dbresult;
+
+	/**
+	 * Rules for preloaded relationships
+	 * @var array
+	 */
+	protected $_with = array();
+
+	/**
+	 * Initialized an Result_ORM with which model to use and which result to
+	 * iterate over
+	 *
+	 * @param string          $model  Model name
+	 * @param Result_Database $dbresult Database result
+	 * @param array           $with Array of rules for preloaded relationships
+	 * @return void
+	 */
+	public function __construct($pixie, $model, $dbresult, $with = array())
+	{
+		$this->pixie = $pixie;
+		$this->_model = $model;
+		$this->_dbresult = $dbresult;
+		foreach ($with as $path => $rel)
+		{
+			$this->_with[] = array(
+				'path' => explode('.', $path),
+				'path_count' => count(explode('.', $path)),
+				'model' => $rel['model'],
+				'columns' => $rel['model']->columns(),
+			);
+		}
+	}
+
+	/**
+	 * Rewinds database cursor to the first row
+	 *
+	 * @return void
+	 */
+	function rewind()
+	{
+		$this->_dbresult->rewind();
+	}
+	
+	/**
+	 * Builds a model instance based on row data.
+	 *
+	 * @param array $data Item data
+	 * @return \PHPixie\ORM\Model Model instance initialized with item data
+	 */
+	public function build_model($data) {
+		
+		$model = $this->pixie->orm->get($this->_model);
+
+		if (empty($data))
+		{
+			return $model;
+		}
+
+		if (empty($this->_with))
+		{
+			return $model->values($data, true);
+		}
+
+
+		$model_data = array();
+		foreach ($model->columns() as $column)
+		{
+			$model_data[$column] = array_shift($data);
+		}
+		$model->values($model_data, true);
+
+		foreach ($this->_with as $rel)
+		{
+			$rel_data = array();
+			foreach ($rel['columns'] as $column)
+			{
+				$rel_data[$column] = array_shift($data);
+			}
+			$rel['model']->values($rel_data, true);
+
+			$owner = $model;
+			foreach ($rel['path'] as $key => $child)
+			{
+				if ($key == $rel['path_count'] - 1)
+				{
+					$owner->cached[$child] = $rel['model'];
+				}
+				else
+				{
+					$owner = $owner->cached[$child];
+				}
+			}
+		}
+
+		return $model;	
+		
+	}
+	
+	/**
+	 * Gets an ORM Model of the current row
+	 *
+	 * @return \PHPixie\ORM\Model Model of the current row of the result set
+	 */
+	public function current()
+	{
+		$data = $this->_dbresult->valid()
+			?((array) $this->_dbresult->current())
+			:null;
+			
+		return $this->build_model($data);
+	}
+
+	/**
+	 * Gets current rows' index number
+	 *
+	 * @return int Row number
+	 */
+	function key()
+	{
+		return $this->_dbresult->key();
+	}
+
+	/**
+	 * Iterates to the next row in the result
+	 *
+	 * @return void
+	 */
+	function next()
+	{
+		$this->_dbresult->next();
+	}
+
+	/**
+	 * Checks if current row is valid.
+	 *
+	 * @return bool returns false if we reach the end of the result set.
+	 */
+	function valid()
+	{
+		return $this->_dbresult->valid();
+	}
+
+	/**
+	 * Returns an array of all rows as ORM objects if $rows is False,
+	 * or just an array of result rows with each row being a standard object,
+	 * this can be useful for functions like json_encode.
+	 *
+	 * @param boolean $rows Whether to return just rows and not ORM objects
+	 * @return array   Array of ORM objects or standard objects representing rows
+	 */
+	public function as_array($rows = false)
+	{
+		if (!$rows)
+		{
+			$arr = array();
+			foreach ($this as $row)
+				$arr[] = $row;
+			return $arr;
+		}
+
+		if (empty($this->_with))
+		{
+			return $this->_dbresult->as_array();
+		}
+
+		$arr = array();
+		$model = $model = $this->pixie->orm->get($this->_model);
+		foreach ($this->_dbresult as $data)
+		{
+			$row = new \stdClass;
+			$data = (array) $data;
+			foreach ($model->columns() as $column)
+			{
+				$row->$column = array_shift($data);
+			}
+
+			foreach ($this->_with as $rel)
+			{
+				$rel_data = new \StdClass;
+				foreach ($rel['columns'] as $column)
+				{
+					$rel_data->$column = array_shift($data);
+				}
+
+				$owner = &$row;
+				foreach ($rel['path'] as $key => $child)
+				{
+					if ($key == $rel['path_count'] - 1)
+					{
+						$owner->$child = $rel_data;
+					}
+					else
+					{
+						$owner = &$owner->$child;
+					}
+				}
+			}
+			$arr[] = $row;
+		}
+
+		return $arr;
+	}
+
+}

+ 26 - 0
php-phpixie/vendor/phpixie/orm/composer.json

@@ -0,0 +1,26 @@
+{
+    "name": "phpixie/orm",
+    "description": "ORM library for PHPixie",
+    "keywords": ["orm", "database"],
+    "homepage": "http://phpixie.com",
+    "type": "library",
+    "license": "BSD",
+    "authors": [
+        {
+            "name": "Roman Tsiupa",
+            "email": "[email protected]",
+            "homepage": "http://dracony.org"
+        }
+    ],
+    "require": {
+        "phpixie/db": "2.*@dev"
+    },
+    "autoload": {
+        "psr-0": {"PHPixie": "classes/"}
+    },
+    "extra": {
+        "branch-alias": {
+            "dev-master": "2.x-dev"
+        }
+    }
+}

+ 10 - 0
php-phpixie/vendor/phpixie/orm/tests/bootstrap.php

@@ -0,0 +1,10 @@
+<?php
+if(!defined('INIT')) {	
+	define('ROOT',dirname(dirname(dirname(dirname(dirname(__FILE__))))));
+	$loader = require_once(ROOT.'/vendor/autoload.php');
+	$loader->add('PHPixie', ROOT.'/vendor/phpixie/core/classes/');
+	$loader->add('PHPixie', ROOT.'/vendor/phpixie/db/classes/');
+	$loader->add('PHPixie',ROOT.'/vendor/phpixie/orm/classes/');
+	define('INIT', true);
+}
+	

+ 6 - 0
php-phpixie/vendor/phpixie/orm/tests/files/extension.php

@@ -0,0 +1,6 @@
+<?php
+namespace Extension {
+	class Test extends \PHPixie\ORM\Extension {
+		public $id;
+	}
+}

+ 23 - 0
php-phpixie/vendor/phpixie/orm/tests/files/fairy_orm.php

@@ -0,0 +1,23 @@
+<?php
+namespace Model {
+	class Fairy extends \PHPixie\ORM\Model
+	{
+
+		public $belongs_to = array('tree');
+		public $connection = 'orm';
+		public $has_many = array(
+			'protects' => array('model' => 'tree', 'key' => 'protector_id'),
+			'friends' => array('model' => 'fairy', 'through' => 'friends', 'key' => 'fairy_id', 'foreign_key' => 'friend_id')
+		);
+		protected $extensions = array(
+			'extension' => '\Extension\Test'
+		);
+		
+		public function get($column)
+		{
+			if ($column == 'test')
+				return 5;
+		}
+
+	}
+}

+ 5 - 0
php-phpixie/vendor/phpixie/orm/tests/files/namespaced_orm.php

@@ -0,0 +1,5 @@
+<?php
+namespace Model\Forest;
+class Fairy extends \PHPixie\ORM\Model {
+	public $connection = 'orm';
+}

+ 11 - 0
php-phpixie/vendor/phpixie/orm/tests/files/nested_orm.php

@@ -0,0 +1,11 @@
+<?php
+namespace Model {
+	class Nested extends \PHPixie\ORM\Model
+	{
+		public $table = 'nested';
+		public $connection = 'orm';
+		protected $extensions = array(
+			'nested' => '\PHPixie\ORM\Extension\Nested'
+		);
+	}
+}

+ 23 - 0
php-phpixie/vendor/phpixie/orm/tests/files/stub_orm.php

@@ -0,0 +1,23 @@
+<?php
+namespace Model{
+	class Stub_ORM
+	{
+
+		public $row;
+		public $loaded;
+		public $cached = array();
+
+		public function values($row, $loaded)
+		{
+			$this->row = $row;
+			$this->loaded = $loaded;
+			return $this;
+		}
+
+		public function columns()
+		{
+			return array('id', 'name');
+		}
+
+	}
+}

+ 39 - 0
php-phpixie/vendor/phpixie/orm/tests/files/test_result.php

@@ -0,0 +1,39 @@
+<?php
+
+Class Test_Result implements Iterator
+{
+
+	public $pos = 0;
+	public $data;
+
+	public function key()
+	{
+		return $this->pos > count($this->data) - 1 ? count($this->data) - 1 : $this->pos;
+	}
+
+	public function valid()
+	{
+		return $this->pos < count($this->data);
+	}
+
+	public function next()
+	{
+		$this->pos++;
+	}
+
+	public function current()
+	{
+		return $this->data[$this->pos];
+	}
+
+	public function as_array()
+	{
+		return $this->data;
+	}
+
+	public function rewind()
+	{
+
+	}
+
+}

+ 13 - 0
php-phpixie/vendor/phpixie/orm/tests/files/tree_orm.php

@@ -0,0 +1,13 @@
+<?php
+namespace Model{
+	class Tree extends \PHPixie\ORM\Model
+	{
+
+		public $has_one = array('fairy');
+		public $connection = 'orm';
+		public $belongs_to = array(
+			'protector' => array('model' => 'fairy', 'key' => 'protector_id')
+		);
+
+	}
+}

+ 205 - 0
php-phpixie/vendor/phpixie/orm/tests/orm/extension/nestedTest.php

@@ -0,0 +1,205 @@
+<?php
+require_once(__DIR__.'/../../files/nested_orm.php');
+
+class ORM_Extension_Nested_Test extends PHPUnit_Framework_TestCase
+{
+	protected $nodes = array();
+	
+	protected function setUp()
+	{
+	
+		$this->db_file = tempnam(sys_get_temp_dir(), 'test.sqlite');
+		$this->conf_file = tempnam(sys_get_temp_dir(), 'test.conf');
+		file_put_contents($this->db_file, '');
+		$db = new PDO('sqlite:'.$this->db_file);
+		$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+		$db->exec("CREATE TABLE nested(id INT PRIMARY_KEY, lpos INT, rpos INT, depth INT)");
+		$this->pixie = $this->getMock('\PHPixie\Pixie',array('find_file'));
+		$this->pixie->expects($this->any())
+                 ->method('find_file')
+                 ->will($this->returnValue($this->conf_file));
+		$this->pixie->db = new \PHPixie\DB($this->pixie);
+		$this->pixie->orm = new \PHPixie\ORM($this->pixie);
+				 
+		$this->pixie->config->set('db.orm.connection', 'sqlite:'.$this->db_file);
+		$this->pixie->config->set('db.orm.driver', 'pdo');
+	}
+	
+	protected function tearDown()
+	{	
+		$db = $this->pixie->db->get('orm');
+		$db->conn = null;
+		unlink($this->db_file);
+		unlink($this->conf_file);
+	}
+	
+	public function testTree() {
+		$n = array();
+		$this->makeNode(1, null);
+		$this->nodeTest(1, 1, 2, 0);
+		
+		$this->makeNode(2, 1);
+		$this->nodeTest(2, 2, 3, 1);
+		$this->nodeTest(1, 1, 4, 0);
+		
+		$this->makeNode(3, 2);
+		//
+		$this->nodeTest(3, 3, 4, 2);
+		$this->nodeTest(2, 2, 5, 1);
+		$this->nodeTest(1, 1, 6, 0);
+		
+		$this->makeNode(4, 2);
+		$this->nodeTest(4, 5, 6, 2);
+		$this->nodeTest(3, 3, 4, 2);
+		$this->nodeTest(2, 2, 7, 1);
+		$this->nodeTest(1, 1, 8, 0);
+		
+		$this->makeNode(5, null);
+		$this->nodeTest(5, 9, 10, 0);
+		$this->nodeTest(4, 5, 6, 2);
+		$this->nodeTest(3, 3, 4, 2);
+		$this->nodeTest(2, 2, 7, 1);
+		$this->nodeTest(1, 1, 8, 0);
+		
+		$this->moveNode(2, 5);
+		
+		$this->nodeTest(5, 3, 10, 0);
+		$this->nodeTest(4, 7, 8, 2);
+		$this->nodeTest(3, 5, 6, 2);
+		$this->nodeTest(2, 4, 9, 1);
+		$this->nodeTest(1, 1, 2, 0);
+		
+		$this->moveNode(4, 1);
+		
+		$this->nodeTest(5, 5, 10, 0);
+		$this->nodeTest(4, 2, 3, 1);
+		$this->nodeTest(3, 7, 8, 2);
+		$this->nodeTest(2, 6, 9, 1);
+		$this->nodeTest(1, 1, 4, 0);
+		
+		$this->moveNode(4, 2);
+		
+		$this->nodeTest(5, 3, 10, 0);
+		$this->nodeTest(4, 7, 8, 2);
+		$this->nodeTest(3, 5, 6, 2);
+		$this->nodeTest(2, 4, 9, 1);
+		$this->nodeTest(1, 1, 2, 0);
+		
+		$this->moveChildren(2, 1);
+		//print_r($this->pixie-> db->get('orm')->execute("SELECT * from nested")->as_array());
+		$this->nodeTest(5, 7, 10, 0);
+		$this->nodeTest(4, 4, 5, 1);
+		$this->nodeTest(3, 2, 3, 1);
+		$this->nodeTest(2, 8, 9, 1);
+		$this->nodeTest(1, 1, 6, 0);
+		
+		
+		$this->moveChildren(1, 2);
+		$this->nodeTest(5, 3, 10, 0);
+		$this->nodeTest(4, 7, 8, 2);
+		$this->nodeTest(3, 5, 6, 2);
+		$this->nodeTest(2, 4, 9, 1);
+		$this->nodeTest(1, 1, 2, 0);
+		
+		$query = $this->nodes[5]->nested->children()->query->query();
+		$this->assertEquals(3, $query[1][0]);
+		$this->assertEquals(10, $query[1][1]);
+		
+		$this->moveChildren(2, null);
+		$this->nodeTest(5, 3, 6, 0);
+		$this->nodeTest(4, 9, 10, 0);
+		$this->nodeTest(3, 7, 8, 0);
+		$this->nodeTest(2, 4, 5, 1);
+		$this->nodeTest(1, 1, 2, 0);
+		
+		$this->moveNode(3, 2);
+		$this->moveNode(4, 2);
+		$this->nodeTest(5, 3, 10, 0);
+		$this->nodeTest(4, 7, 8, 2);
+		$this->nodeTest(3, 5, 6, 2);
+		$this->nodeTest(2, 4, 9, 1);
+		$this->nodeTest(1, 1, 2, 0);
+		
+		$this->deleteNode(3);
+		$this->nodeTest(5, 3, 8, 0);
+		$this->nodeTest(4, 5, 6, 2);
+		$this->nodeTest(2, 4, 7, 1);
+		$this->nodeTest(1, 1, 2, 0);
+		
+		$this->deleteNode(2);
+		$this->nodeTest(5, 3, 4, 0);
+		$this->nodeTest(1, 1, 2, 0);
+		
+		$this->deleteNode(1);
+		$this->nodeTest(5, 1, 2, 0);
+		
+		$this->deleteNode(5);
+		$this->assertEquals(true,empty($this->nodes));
+		
+		$n = new \Model\Nested($this->pixie);
+		$except = false;
+		try {
+			$n->nested->prepare_delete();
+		}catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true, $except);
+		
+		$except = false;
+		try {
+			$n->nested->move_children(null);
+		}catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true, $except);
+		
+		$except = false;
+		try {
+			$n->nested->children();
+		}catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true,$except);
+		
+	}
+	
+	protected function refreshNodes() {
+		$nodes = new \Model\Nested($this->pixie);
+		$nodes = $nodes->find_all();
+		$this->nodes = array();
+		foreach($nodes as $node) 
+			$this->nodes[$node->id] = $node;
+	}
+	
+	protected function makeNode($id, $parent = null) {
+		$n = new \Model\Nested($this->pixie);
+		$n->id = $id;
+		$n->nested->prepare_append($parent?$this->nodes[$parent]:null)->save();
+		$this->refreshNodes();
+		$this->nodes[$id] = $n;
+		return $n;
+	}
+	
+	protected function moveNode($id, $parent) {
+		$this->nodes[$id]->nested->prepare_append($parent?$this->nodes[$parent]:null);
+		$this->nodes[$id]->save();
+		$this->refreshNodes();
+	}
+	
+	protected function moveChildren($id, $parent) {
+		$this->nodes[$id]->nested->move_children($parent?$this->nodes[$parent]:null);
+		$this->refreshNodes();
+	}
+	
+	protected function deleteNode($id) {
+		$this->nodes[$id]->nested->prepare_delete()->delete();
+		$this->refreshNodes();
+	}
+	
+	protected function nodeTest($id, $lpos, $rpos, $depth) {
+		$this->assertEquals($lpos, $this->nodes[$id]->lpos);
+		$this->assertEquals($rpos, $this->nodes[$id]->rpos);
+		$this->assertEquals($depth, $this->nodes[$id]->depth);
+	}
+	
+}

+ 370 - 0
php-phpixie/vendor/phpixie/orm/tests/orm/modelTest.php

@@ -0,0 +1,370 @@
+<?php
+require_once(__DIR__.'/../files/extension.php');
+require_once(__DIR__.'/../files/tree_orm.php');
+require_once(__DIR__.'/../files/fairy_orm.php');
+require_once(__DIR__.'/../files/namespaced_orm.php');
+
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator on 2013-02-08 at 21:28:15.
+ */
+class ORM_Model_Test extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var ORM
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+	
+		$this->db_file = tempnam(sys_get_temp_dir(), 'test.sqlite');
+		$this->conf_file = tempnam(sys_get_temp_dir(), 'test.conf');
+		file_put_contents($this->db_file, '');
+		$db = new PDO('sqlite:'.$this->db_file);
+		$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+		$db->exec("CREATE TABLE fairies(id INT PRIMARY_KEY,name VARCHAR(255),tree_id INT)");
+		$db->exec("CREATE TABLE trees(id INT PRIMARY_KEY,name VARCHAR(255),protector_id INT)");
+		$db->exec("CREATE TABLE friends(fairy_id INT,friend_id INT)");
+
+		$db->exec("INSERT INTO fairies(id,name,tree_id) VALUES (1,'Tinkerbell',1)");
+		$db->exec("INSERT INTO fairies(id,name,tree_id) VALUES (2,'Trixie',2)");
+
+		$db->exec("INSERT INTO trees(id,name,protector_id) VALUES (1,'Oak',2)");
+		$db->exec("INSERT INTO trees(id,name,protector_id) VALUES (2,'Willow',2)");
+
+		$db->exec("INSERT INTO friends(fairy_id,friend_id) VALUES (1,2)");
+
+		$this->pixie = $this->getMock('\PHPixie\Pixie',array('find_file'));
+		$this->pixie->expects($this->any())
+                 ->method('find_file')
+                 ->will($this->returnValue($this->conf_file));
+		$this->pixie->db = new \PHPixie\DB($this->pixie);
+		$this->pixie-> orm = new \PHPixie\ORM($this->pixie);
+				 
+		$this->pixie->config->set('db.orm.connection', 'sqlite:'.$this->db_file);
+		$this->pixie->config->set('db.orm.driver', 'pdo');
+
+		$this->fairies = new \Model\Fairy($this->pixie);
+		$this->trees = new \Model\Tree($this->pixie);
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{	
+		$db = $this->pixie->db->get('orm');
+		$db->conn = null;
+		unlink($this->db_file);
+		unlink($this->conf_file);
+	}
+
+	/**
+	 * @covers ORM::__call
+	 * @todo   Implement test__call().
+	 */
+	public function test__call()
+	{
+		$this->fairies->limit(6);
+		$this->fairies->offset(5);
+		$this->assertEquals(6, $this->fairies->limit());
+		$this->assertEquals(5, $this->fairies->offset());
+		$this->fairies->where('id', 8);
+		$this->fairies->order_by('id', 'desc');
+	}
+
+	/**
+	 * @covers ORM::find_all
+	 * @todo   Implement testFind_all().
+	 */
+	public function testFind_all()
+	{
+
+		$this->assertEquals('Trixie', $this->pixie->orm->get('fairy')->where('id', 2)->find_all()->current()->name);
+	}
+
+	/**
+	 * @covers ORM::find
+	 * @todo   Implement testFind().
+	 */
+	public function testFind()
+	{
+		$this->assertEquals('Trixie', $this->fairies->where('id', 2)->find()->name);
+	}
+
+	/**
+	 * @covers ORM::count_all
+	 * @todo   Implement testCount_all().
+	 */
+	public function testCount_all()
+	{
+		$this->assertEquals(2, $this->fairies->count_all());
+		$this->assertEquals(0, $this->fairies->find()->protects->count_all());
+		$this->assertEquals(1, $this->fairies->where('id', 2)->count_all());
+		$this->assertEquals(2, $this->pixie->orm->get('fairy')->where('id', 2)->protects->count_all());
+	}
+
+	/**
+	 * @covers ORM::loaded
+	 * @todo   Implement testLoaded().
+	 */
+	public function testLoaded()
+	{
+		$this->assertEquals(false, $this->fairies->loaded());
+		$this->assertEquals(true, $this->fairies->find()->loaded());
+	}
+
+	/**
+	 * @covers ORM::as_array
+	 * @todo   Implement testAs_array().
+	 */
+	public function testAs_array()
+	{
+		$arr = $this->fairies->find()->as_array();
+		$this->assertEquals('Tinkerbell', $arr['name']);
+	}
+
+	/**
+	 * @covers ORM::query
+	 * @todo   Implement testQuery().
+	 */
+	public function testQuery()
+	{
+		$this->fairies->limit(5);
+		$this->assertEquals(5, $this->fairies->query()->limit());
+	}
+
+	/**
+	 * @covers ORM::get
+	 * @todo   Implement testGet().
+	 */
+	public function testGet()
+	{
+		$dd = array('fff' => 44);
+
+		$fairy = $this->fairies->find();
+		$fairy->test;
+		$this->assertEquals(5, $fairy->cached['test']);
+	}
+
+	/**
+	 * @covers ORM::__get
+	 * @todo   Implement test__get().
+	 */
+	public function test__get()
+	{
+		$this->assertEquals('Oak', $this->fairies->tree->find_all()->current()->name);
+		$this->assertEquals('Oak', $this->fairies->find()->tree->name);
+		$this->assertEquals('Tinkerbell', $this->trees->find()->fairy->name);
+		$this->assertEquals('Tinkerbell', $this->trees->find()->fairy->name);
+		$protects = $this->fairies->where('id', 2)->find()->protects->find_all();
+		$this->assertEquals('Oak', $protects->current()->name);
+		$protects->next();
+		$this->assertEquals('Willow', $protects->current()->name);
+		$this->assertEquals('Trixie', $this->trees->protector->find()->name);
+
+		$this->assertEquals('Trixie', $this->pixie->orm->get('fairy')->find()->friends->find()->name);
+	}
+
+	/**
+	 * @covers ORM::add
+	 * @todo   Implement testAdd().
+	 */
+	public function testAdd()
+	{
+		$fairy = $this->pixie->orm->get('fairy')->find();
+		$fairy->add('tree', $this->pixie->orm->get('tree')->where('id', 2)->find());
+		$fairy->save();
+		$this->assertEquals('Willow', $this->pixie->orm->get('fairy')->find()->tree->name);
+
+		$fairy = $this->pixie->orm->get('fairy');
+		$fairy->add('tree', $this->pixie->orm->get('tree')->where('id', 2)->find());
+		$fairy->id = 3;
+		$fairy->save();
+		$fairy = $this->pixie->orm->get('fairy', 3);
+		$this->assertEquals('Willow', $fairy->tree->name);
+
+		$tree = $this->pixie->orm->get('tree')->find();
+		$fairy = $this->pixie->orm->get('fairy');
+		$tree->fairy = $fairy;
+		$fairy->id = 4;
+		$fairy->save();
+		$this->assertEquals('Oak', $this->pixie->orm->get('fairy', 4)->tree->name);
+
+
+		$fairy = $this->pixie->orm->get('fairy')->where('id', 2)->find();
+		$fairy->add('friends', $this->pixie->orm->get('fairy')->where('id', 1)->find());
+		$this->assertEquals('Tinkerbell', $this->pixie->orm->get('fairy')->where('id', 2)->find()->friends->find()->name);
+	}
+
+	/**
+	 * @covers ORM::__set
+	 * @todo   Implement test__set().
+	 */
+	public function test__set()
+	{
+		$fairy = $this->fairies->find();
+		$fairy->name = 'test';
+		$this->assertEquals('test', $fairy->name);
+
+		$fairy = $this->pixie->orm->get('fairy')->where('id', 2)->find();
+		$fairy->friends = $this->pixie->orm->get('fairy')->where('id', 1)->find();
+		$this->assertEquals('Tinkerbell', $this->pixie->orm->get('fairy')->where('id', 2)->find()->friends->find()->name);
+
+		$this->pixie->orm->get('tree')->where('id', 2)->find()->fairy = $this->pixie->orm->get('fairy')->find();
+		$this->pixie->orm->get('tree')->find()->fairy = $this->pixie->orm->get('fairy')->where('id', 2)->find();
+
+		$this->assertEquals('Trixie', $this->pixie->orm->get('tree')->find()->fairy->name);
+	}
+
+	/**
+	 * @covers ORM::remove
+	 * @todo   Implement testRemove().
+	 */
+	public function testRemove()
+	{
+		$fairy = $this->pixie->orm->get('fairy')->find();
+		$fairy->remove('tree');
+
+		$this->assertEquals(false, $fairy->tree->loaded());
+
+		$fairy->remove('friends', $this->pixie->orm->get('fairy')->where('id', 2)->find());
+		$this->assertEquals(false, $fairy->friends->find()->loaded());
+
+		$fairy = $this->pixie->orm->get('fairy')->where('id', 2)->find();
+		$fairy->remove('protects', $this->pixie->orm->get('tree')->where('id', 1)->find());
+		$this->assertEquals('Willow', $fairy->protects->find()->name);
+	}
+	
+	public function testIsset() {
+		$fairy = $this->fairies->find();
+		$this->assertEquals(true, isset($fairy->id));
+		$this->assertEquals(true, isset($fairy->protects));
+		$this->assertEquals(false, isset($fairy->bogus));
+		$this->assertEquals(true, isset($fairy->test));
+	}
+	/**
+	 * @covers ORM::columns
+	 * @todo   Implement testColumns().
+	 */
+	public function testColumns()
+	{
+		$cols = $this->fairies->columns();
+		$this->assertEquals('id', $cols[0]);
+		$this->assertEquals('name', $cols[1]);
+		$this->assertEquals('tree_id', $cols[2]);
+	}
+
+	/**
+	 * @covers ORM::id
+	 */
+	public function testId()
+	{
+		$fairy = $this->fairies->find();
+		$this->assertEquals(1,$fairy->id());
+	}
+	/**
+	 * @covers ORM::with
+	 * @todo   Implement testWith().
+	 */
+	public function testWith()
+	{
+		$res = $this->fairies->with ('tree', 'tree.protector')->find();
+		$this->assertEquals('Oak', $res->cached['tree']->name);
+		$this->assertEquals('Trixie', $res->cached['tree']->cached['protector']->name);
+	}
+
+	/**
+	 * @covers ORM::delete
+	 * @todo   Implement testDelete().
+	 */
+	public function testDelete()
+	{
+		$this->fairies->find()->delete();
+		$this->assertEquals('Trixie', $this->fairies->find()->name);
+	}
+
+	/**
+	 * @covers ORM::delete
+	 * @todo   Implement testDelete().
+	 */
+	public function testDeleteException()
+	{
+		$except = false;
+		try {
+			$this->fairies->delete();
+		} catch (Exception $e) {
+			$except = true;
+		}
+		$this->assertEquals(true, $except);
+	}
+
+	/**
+	 * @covers ORM::delete_all
+	 * @todo   Implement testDelete_all().
+	 */
+	public function testDelete_all()
+	{
+		$this->fairies->delete_all();
+		$this->assertEquals(false, $this->fairies->find()->loaded());
+	}
+
+	/**
+	 * @covers ORM::save
+	 * @todo   Implement testSave().
+	 */
+	public function testSave()
+	{
+		$fairy = $this->fairies->find();
+		$fairy->name = 'test';
+		$fairy->save();
+		$this->assertEquals('test', $this->fairies->find()->name);
+
+		$fairy = $this->pixie->orm->get('fairy');
+		$fairy->name = 'test2';
+		$fairy->id = 3;
+		$fairy->save();
+		$this->assertEquals('test2', $this->fairies->order_by('id', 'desc')->find()->name);
+	}
+
+	/**
+	 * @covers ORM::values
+	 * @todo   Implement testValues().
+	 */
+	public function testValues()
+	{
+		$fairy = $this->fairies->find();
+		$fairy->values(array('id' => 1, 'name' => 'Trixie'));
+		$this->assertEquals('Trixie', $fairy->name);
+	}
+	
+	public function testExtension() {
+		$fairy = $this->fairies->find();
+		$fairy->extension->id = 1;
+		$this->assertEquals(1,$fairy->extension->id);
+	}
+	/**
+	 * @covers $this->pixie->orm->get
+	 * @todo   Implement testFactory().
+	 */
+	public function testFactory()
+	{
+		$this->assertEquals('fairy', $this->pixie->orm->get('fairy')->model_name);
+	}
+	
+	public function testModel_key() {
+		$this->assertEquals('forest_fairy_id', $this->pixie->orm->get('fairy')->model_key('forest\fairy'));
+	}
+	
+	public function testNamespaceTable() {
+		$this->assertEquals('forest_fairies', $this->pixie->orm->get('forest\fairy')->table);
+	}
+
+}

+ 76 - 0
php-phpixie/vendor/phpixie/orm/tests/orm/ormTest.php

@@ -0,0 +1,76 @@
+<?php
+require_once(__DIR__.'/../files/extension.php');
+require_once(__DIR__.'/../files/tree_orm.php');
+require_once(__DIR__.'/../files/fairy_orm.php');
+
+/**
+ * Generated by PHPUnit_SkeletonGenerator on 2013-02-07 at 10:14:10.
+ */
+class ORM_Test extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Expression_Database
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		
+		$this->db_file = tempnam(sys_get_temp_dir(), 'test.sqlite');
+		$this->conf_file = tempnam(sys_get_temp_dir(), 'test.conf');
+		file_put_contents($this->db_file, '');
+		$db = new PDO('sqlite:'.$this->db_file);
+		$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+		$db->exec("CREATE TABLE fairies(id INT PRIMARY_KEY,name VARCHAR(255),tree_id INT)");
+		$db->exec("CREATE TABLE trees(id INT PRIMARY_KEY,name VARCHAR(255),protector_id INT)");
+		$db->exec("CREATE TABLE friends(fairy_id INT,friend_id INT)");
+
+		$db->exec("INSERT INTO fairies(id,name,tree_id) VALUES (1,'Tinkerbell',1)");
+		$db->exec("INSERT INTO fairies(id,name,tree_id) VALUES (2,'Trixie',2)");
+
+		$db->exec("INSERT INTO trees(id,name,protector_id) VALUES (1,'Oak',2)");
+		$db->exec("INSERT INTO trees(id,name,protector_id) VALUES (2,'Willow',2)");
+
+		$db->exec("INSERT INTO friends(fairy_id,friend_id) VALUES (1,2)");
+
+		$this->pixie = $this->getMock('\PHPixie\Pixie',array('find_file'));
+		$this->pixie->expects($this->any())
+                 ->method('find_file')
+                 ->will($this->returnValue($this->conf_file));
+		$this->pixie->db = new \PHPixie\DB($this->pixie);
+		$this->pixie-> orm = new \PHPixie\ORM($this->pixie);
+				 
+		$this->pixie->config->set('db.orm.connection', 'sqlite:'.$this->db_file);
+		$this->pixie->config->set('db.orm.driver', 'pdo');
+
+		$this->fairies = new \Model\Fairy($this->pixie);
+		$this->trees = new \Model\Tree($this->pixie);
+		$this->object = $this->pixie-> orm;
+	}
+	
+	protected function tearDown()
+	{	
+		$db = $this->pixie->db->get('orm');
+		$db->conn = null;
+		unlink($this->db_file);
+		unlink($this->conf_file);
+	}
+	
+	public function testGet() {
+		$this->assertEquals('Model\Fairy', get_class($this->object->get('fairy')));
+		$this->assertEquals('Model\Tree', get_class($this->object->get('tree')));
+		$this->assertEquals(1, $this->object->get('fairy',1)->id);
+	}
+	
+	public function testResult() {
+		$this->assertEquals('PHPixie\ORM\Result', get_class($this->object->result('fairy',null)));
+	}
+	
+
+	
+}

+ 158 - 0
php-phpixie/vendor/phpixie/orm/tests/orm/resultTest.php

@@ -0,0 +1,158 @@
+<?php
+
+require_once(__DIR__.'/../files/test_result.php');
+require_once(__DIR__.'/../files/stub_orm.php');
+/**
+ * Generated by PHPUnit_SkeletonGenerator on 2013-02-08 at 13:27:44.
+ */
+class ORM_Result_Test extends PHPUnit_Framework_TestCase
+{
+
+	/**
+	 * @var Result_ORM
+	 */
+	protected $object;
+
+	/**
+	 * Sets up the fixture, for example, opens a network connection.
+	 * This method is called before a test is executed.
+	 */
+	protected function setUp()
+	{
+		$this->stub = new Test_Result;
+		$this->stub->data = array(
+			(object) array('id' => 1, 'name' => 'Trixie'),
+			(object) array('id' => 2, 'name' => 'Tinkerbell')
+		);
+		$this->pixie = new \PHPixie\Pixie();
+		$this->pixie->db = $this->getMockBuilder('\PHPixie\DB')
+				->disableOriginalConstructor()
+				->getMock();
+		$this->pixie->orm = new \PHPixie\ORM($this->pixie);
+		$this->object = new \PHPixie\ORM\Result($this->pixie,'Stub_Orm', $this->stub);
+	}
+
+	/**
+	 * Tears down the fixture, for example, closes a network connection.
+	 * This method is called after a test is executed.
+	 */
+	protected function tearDown()
+	{
+
+	}
+
+	/**
+	 * @covers Result_ORM::current
+	 * @todo   Implement testCurrent().
+	 */
+	public function testCurrent()
+	{
+
+		$row = $this->object->current()->row;
+		;
+		$this->assertArrayHasKey('id', $row);
+		$this->assertArrayHasKey('name', $row);
+		$this->assertEquals(1, $row['id']);
+		$this->assertEquals('Trixie', $row['name']);
+		$this->object->next();
+		$row = $this->object->current()->row;
+		$this->assertArrayHasKey('id', $row);
+		$this->assertArrayHasKey('name', $row);
+		$this->assertEquals(2, $row['id']);
+		$this->assertEquals('Tinkerbell', $row['name']);
+	}
+
+	/**
+	 * @covers Result_ORM::key
+	 * @todo   Implement testKey().
+	 */
+	public function testKey()
+	{
+		$this->assertEquals(0, $this->object->key());
+		$this->object->next();
+		$this->assertEquals(1, $this->object->key());
+		$this->object->next();
+		$this->assertEquals(1, $this->object->key());
+	}
+
+	public function testValid()
+	{
+		$this->assertEquals(true, $this->object->valid());
+		$this->object->next();
+		$this->assertEquals(true, $this->object->valid());
+		$this->object->next();
+		$this->assertEquals(false, $this->object->valid());
+	}
+
+	public function testAs_arrayArray()
+	{
+		$arr = $this->object->as_array(true);
+
+		foreach (array('Trixie', 'Tinkerbell') as $key => $name)
+		{
+			$this->assertArrayHasKey($key, $arr);
+			$row = (array) $arr[$key];
+			$this->assertArrayHasKey('name', $row);
+			$this->assertEquals($name, $row['name']);
+		}
+	}
+
+	public function testAs_arrayObject()
+	{
+
+		$arr = $this->object->as_array();
+
+		foreach (array('Trixie', 'Tinkerbell') as $key => $name)
+		{
+			$this->assertArrayHasKey($key, $arr);
+			$row = $arr[$key];
+			$this->assertArrayHasKey('name', $row->row);
+			$this->assertEquals($name, $row->row['name']);
+		}
+	}
+
+	public function test_with()
+	{
+		$this->stub->data = array(
+			(object) array('id' => 1, 'name' => 'Trixie', 'id1' => 11, 'name1' => 'Trixie1', 'id2' => 12, 'name2' => 'Trixie2'),
+			(object) array('id' => 1, 'name' => 'Tinkerbell', 'id1' => 11, 'name1' => 'Tinkerbell1', 'id2' => 12, 'name2' => 'Tinkerbell2')
+		);
+
+		$this->object = new \PHPixie\ORM\Result($this->pixie, 'Stub_Orm', $this->stub, array(
+			'tester' => array('model' => new \Model\Stub_Orm),
+			'tester.another' => array('model' => new \Model\Stub_Orm)
+		));
+		foreach (array('Trixie', 'Tinkerbell') as $name)
+		{
+			$cur = $this->object->current();
+			$this->assertEquals($name, $cur->row['name']);
+			$this->assertArrayHasKey('tester', $cur->cached);
+
+			$this->assertEquals($name.'1', $cur->cached['tester']->row['name']);
+			$this->assertArrayHasKey('another', $cur->cached['tester']->cached);
+			$this->assertEquals($name.'2', $cur->cached['tester']->cached['another']->row['name']);
+			$this->object->next();
+		}
+	}
+
+	public function test_withArray()
+	{
+		$this->stub->data = array(
+			(object) array('id' => 1, 'name' => 'Trixie', 'id1' => 11, 'name1' => 'Trixie1', 'id2' => 12, 'name2' => 'Trixie2'),
+			(object) array('id' => 1, 'name' => 'Tinkerbell', 'id1' => 11, 'name1' => 'Tinkerbell1', 'id2' => 12, 'name2' => 'Tinkerbell2')
+		);
+		$this->object = new \PHPixie\ORM\Result($this->pixie,'Stub_Orm', $this->stub, array(
+			'tester' => array('model' => $this->pixie->orm->get('Stub_Orm')),
+			'tester.another' => array('model' => $this->pixie->orm->get('Stub_Orm'))
+		));
+		$arr = $this->object->as_array(true);
+		foreach (array('Trixie', 'Tinkerbell') as $key => $name)
+		{
+			$this->assertArrayHasKey($key, $arr);
+			$this->assertEquals($name, $arr[$key]->name);
+			$this->assertEquals($name.'1', $arr[$key]->tester->name);
+			$this->assertEquals($name.'2', $arr[$key]->tester->another->name);
+		}
+	}
+
+}

+ 1 - 0
php-phpixie/vendor/phpixie/orm/tests/phpunit.xml

@@ -0,0 +1 @@
+<phpunit bootstrap="bootstrap.php"></phpunit>

+ 9 - 0
php-phpixie/web/.htaccess

@@ -0,0 +1,9 @@
+RewriteEngine On
+RewriteBase /
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule .* index.php?$0 [PT,L,QSA]
+
+
+
+
+

+ 11 - 0
php-phpixie/web/index.php

@@ -0,0 +1,11 @@
+<?php
+$root = dirname(__DIR__);
+$loader = require $root.'/vendor/autoload.php';
+$loader->add('', $root.'/classes/');
+$loader->add('PHPixie', $root.'/vendor/phpixie/core/classes/');
+$loader->add('PHPixie', $root.'/vendor/phpixie/db/classes/');
+$loader->add('PHPixie',$root.'/vendor/phpixie/orm/classes/');
+
+$pixie = new \App\Pixie();
+$pixie->bootstrap($root)->http_request()->execute()->send_headers()->send_body();
+?>