diff --git a/.gitignore b/.gitignore index cd2946a..8badbff 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ Desktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ +# PHPStorm folder +.idea/* + # Windows Installer files *.cab *.msi diff --git a/.htaccess b/.htaccess new file mode 100644 index 0000000..6222188 --- /dev/null +++ b/.htaccess @@ -0,0 +1,4 @@ +Options -MultiViews +RewriteEngine On +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule ^ index.php [QSA,L] \ No newline at end of file diff --git a/AroMVC/AroModel.php b/AroMVC/AroModel.php new file mode 100644 index 0000000..937b50a --- /dev/null +++ b/AroMVC/AroModel.php @@ -0,0 +1,67 @@ +initialize(); + + return $new; + } + public static function withRow(array $row) { + $new = new static(); + $new->initialize(); + array_walk($row, function($v, $k) use (&$new) { + $new->rawData[strtolower($k)] = $v; + }); + return $new; + } + + protected abstract function initialize(); + + public function __get(string $name) { + $name = strtolower($name); + + if(array_key_exists($name, $this->hooks)) + return $this->hooks[$name](); + else if(array_key_exists($name, $this->associations)) + return $this->rawData[$this->associations[$name]]; + else if(array_key_exists($name, $this->rawData)) + return $this->rawData[$name]; + else return null; + } + + public function __set(string $name, $value) { + $name = strtolower($name); + + if(array_key_exists($name, $this->associations)) + $rawData[$this->associations[$name]] = $value; + else if(array_key_exists($name, $this->rawData)) + $rawData[$name] = $value; + else + throw new \Exception("Cannot set the value for property '$name'."); + } + + protected function addHook(string $name, $func) { + $this->hooks[strtolower($name)] = $func; + } + + protected function addAssociation(string $associationName, string $rawName) { + $this->associations[strtolower($associationName)] = strtolower($rawName); + } + + protected function update() { + + } + + protected function delete() { + + } +} \ No newline at end of file diff --git a/AroMVC/Database.php b/AroMVC/Database.php new file mode 100644 index 0000000..7d94b33 --- /dev/null +++ b/AroMVC/Database.php @@ -0,0 +1,9 @@ +allowConditionals) + throw new \Exception("Query type does not allow AND/OR subclauses"); + + array_push($this->query, "AND", $condition); + } + + public function or(string $condition) { + if(!$this->allowConditionals) + throw new \Exception("Query type does not allow AND/OR subclauses"); + + array_push($this->query, "OR", $condition); + } + + public function execute(array $params) { + // TODO execution logic + var_dump($this->query); + } + + protected function setFlag(int $flag) { + $this->flags = $this->flags | $flag; + } + + protected function clearFlag(int $flag) { + $this->flags = $this->flags & ~$flag; + } + + protected function checkFlag(int $flag): bool { + return ($this->flags & $flag) != 0; + } + + protected function checkPast(int $flag): bool { + return ~(($flag - 1) | $flag) & $this->flags != 0; + } + + protected function checkForOrPast(int $flag): bool { + return $this->checkFlag($flag) || $this->checkPast($flag); + } +} \ No newline at end of file diff --git a/AroMVC/Router.php b/AroMVC/Router.php new file mode 100644 index 0000000..1c985bf --- /dev/null +++ b/AroMVC/Router.php @@ -0,0 +1,6 @@ +query = ["SELECT", $selection]; + } + + public function execute(array $params): Selectable { + if($this->checkFlag(AMVC_QRY_SEL_NEEDON)) + throw new \Exception("JOIN clause declared in query with no matching ON clause"); + + if($this->checkFlag(AMVC_QRY_SEL_GROUP) && !$this->checkFlag(AMVC_QRY_SEL_ORDER)) { + if($this->checkFlag(AMVC_QRY_SEL_HAVING)) { + $having = array_search("HAVING", $this->query); + array_splice($this->query, $having + 2, 0, ["ORDER BY", "null"]); + } else { + $group = array_search("GROUP BY", $this->query); + array_splice($this->query, $group + 2, 0, ["ORDER BY", "null"]); + } + } + + parent::execute($params); + return $this; + } + + protected function checkFrom() { + if(!$this->checkFlag(AMVC_QRY_SEL_FROM)) + throw new \Exception("FROM clause must come first in a SELECT query"); + } + + public function from(string $where): Selectable { + if($this->checkFlag(AMVC_QRY_SEL_FROM)) + throw new \Exception("Cannot declare second FROM clause on a SELECT query"); + + $this->setFlag(AMVC_QRY_SEL_FROM); + array_push($this->query, "FROM", $where); + return $this; + } + + public function join(string $type, string $table): Selectable { + $this->checkFrom(); + if($this->checkPast(AMVC_QRY_SEL_JOINS)) + throw new \Exception("Invalid JOIN clause, must proceed FROM clause"); + + $this->setFlag(AMVC_QRY_SEL_JOINS); + $this->setFlag(AMVC_QRY_SEL_NEEDON); + array_push($this->query, $type, $table); + return $this; + } + + public function on(string $condition): Selectable { + if(!$this->checkFlag(AMVC_QRY_SEL_NEEDON)) + throw new \Exception("Cannot declare ON clause without prior JOIN clause"); + + $this->clearFlag(AMVC_QRY_SEL_NEEDON); + array_push($this->query, "ON", $condition); + return $this; + } + + public function using($columns): Selectable { + if(!$this->checkFlag(AMVC_QRY_SEL_NEEDON)) + throw new \Exception("Cannot declare USING clause without prior JOIN clause"); + + if(is_array($columns)) + $columns = implode(",", $columns); + + $this->clearFlag(AMVC_QRY_SEL_NEEDON); + array_push($this->query, "USING", "({$columns})"); + return $this; + } + + public function where(string $condition): Selectable { + $this->checkFrom(); + if($this->checkForOrPast(AMVC_QRY_SEL_WHERE)) + throw new \Exception("Duplicate or misplaced WHERE clause in SELECT query"); + + $this->setFlag(AMVC_QRY_SEL_WHERE); + array_push($this->query, "WHERE", $condition); + return $this; + } + + public function and(string $condition): Selectable { + if(!$this->checkFlag(AMVC_QRY_SEL_FROM)) + throw new \Exception("Cannot use AND subclause until FROM clause has been declared in SELECT query"); + + parent::and($condition); + return $this; + } + + public function or(string $condition): Selectable { + $this->checkFrom(); + parent::or($condition); + return $this; + } + + public function groupBy($columns): Selectable { + $this->checkFrom(); + if($this->checkForOrPast(AMVC_QRY_SEL_GROUP)) + throw new \Exception("Duplicate or misplaced GROUP BY clause in SELECT query"); + + if(is_array($columns)) + $columns = implode(",", $columns); + + $this->setFlag(AMVC_QRY_SEL_GROUP); + array_push($this->query, "GROUP BY", $columns); + return $this; + } + + public function having(string $condition): Selectable { + $this->checkFrom(); + if($this->checkForOrPast(AMVC_QRY_SEL_HAVING)) + throw new \Exception("Duplicate or misplaced HAVING clause in SELECT query"); + + array_push($this->query, "HAVING", $condition); + return $this; + } + + public function orderBy($columns): Selectable { + $this->checkFrom(); + if($this->checkForOrPast(AMVC_QRY_SEL_ORDER)) + throw new \Exception("Duplicate or misplaced ORDER BY clause in SELECT query"); + + if(is_array($columns)) + $columns = implode(",", $columns); + + $this->setFlag(AMVC_QRY_SEL_ORDER); + array_push($this->query, "ORDER BY", $columns); + return $this; + } + + public function limit(int $count, int $offset = 0): Selectable { + $this->checkFrom(); + if($this->checkForOrPast(AMVC_QRY_SEL_LIMIT)) + throw new \Exception("Duplicate or misplaced LIMIT clause in SELECT query"); + + $this->setFlag(AMVC_QRY_SEL_LIMIT); + array_push($this->query, "LIMIT", "$offset,$count"); + return $this; + } + + public function asArray() { + if($this->results == null) + throw new \Exception("Cannot return results from a query that has not executed."); + + return $this->results; + } + + public function asModels($obj) { + if($this->results == null) + throw new \Exception("Cannot return results from a query that has not executed."); + + $type = new \ReflectionClass($obj); + if(!$type->isSubclassOf("\\AroMVC\\Core\\AroModel")) + throw new \Exception("Cannot instantiate non-model object."); + + foreach($this->results as $result) + yield $type->getMethod("withRow")->invoke(null, $result); + } +} \ No newline at end of file diff --git a/Controllers/Home.php b/Controllers/Home.php new file mode 100644 index 0000000..a86b135 --- /dev/null +++ b/Controllers/Home.php @@ -0,0 +1,5 @@ +from("Companies") + ->where("`name` = ?") + ->or("`id` = ?") + ->execute(["dekko", 12]) + ->asModels(new Company);