find($class); } protected function reset(): Model { $resets = ['columns', 'joins', 'conditions', 'groups', 'orders', 'having', 'limit', 'offset']; foreach ($resets as $r) { $this->{$r} = null; } return $this; } public function create(string $model_class, array $data = null): bool|ModelInterface { // Check if it already exists if ($data !== null) { $model = $this->find($model_class); foreach ($data as $f => $v) { $model = $model->where([[$f, $v]]); } $model = $model->one(); if ($model !== false and $model !== null) { return $model; } } $model = BaseModel::factory($model_class)->create($data); if (is_a($model, \ORMWrapper::class)) { $model = $model->find_one(); } $model->setFactory($this); return $model; } protected string $class; public function find(string $class): Model { $this->reset(); if (!class_exists($class)) { throw new InvalidArgumentException("Model {$class} not found."); } $this->class = $class; return $this; } protected ?array $columns; public function select($columns): Model { if (!is_array($columns)) { $columns = [$columns]; } foreach ($columns as $c) { $this->addColumn($c); } return $this; } protected function addColumn($column) { $col = [ 'table' => '', 'column' => $column ]; if (is_array($column)) { $col['table'] = $column['table'] ?? $column[0]; $col['column'] = $column['column'] ?? $column[1]; } $this->columns []= $col; } protected function parseColumns(ORM $orm): ORM { if ($this->columns === null) { return $orm; } foreach ($this->columns as $column) { $orm = $orm->select("{$column['table']}.{$column['column']}"); } return $orm; } protected ?array $joins; public function join($joins): Model { foreach ($joins as $join) { $this->addJoin($join); } return $this; } protected function addJoin($join) { $map = [ 'table' => ['table', 't', 0], 'from' => ['from', 'f', 1], 'to' => ['to', 2], 'operator' => ['operator', 'op', 'o', 3], 'type' => 'type', 'alias' => 'alias', 'params' => ['parameters', 'params'] ]; $defaults = ['operator' => '=', 'type' => 'inner']; $required = ['table', 'from', 'to', 'operator', 'type']; $j = []; foreach ($join as $key => $val) { $k = -1; foreach ($map as $i => $m) { if (is_array($m)) { if (in_array($key, $m)) { $k = $i; break; } continue; } if ($m == $key) { $k = $i; } } $j[$k] = $val; } foreach ($defaults as $key => $val) { if (!isset($j[$key])) { $j[$key] = $val; } } foreach ($required as $key) { if (!isset($j[$key])) { throw new InvalidArgumentException("Missing {$key} when joining in " . get_class()); } } $this->joins []= (object) $j; } protected function parseJoins(ORM $orm): ORM { if ($this->joins === null) { return $orm; } foreach ($this->joins as $join) { $method = match(strtolower($join->type)) { 'raw' => 'rawJoin', 'inner' => 'innerJoin', 'left', 'left outer', 'left_outer', 'leftouter' => 'leftOuterJoin', 'right', 'right outer', 'right_outer', 'rightouter' => 'rightOuterJoin', 'full', 'full outer', 'full_outer', 'fullouter', 'outer' => 'fullOuterJoin' }; if (strtolower($join->type) == 'raw') { if (isset($join->params)) { if (isset($join->alias)) { $orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to], $join->alias, $join->params); } else { $orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to], $join->params); } } else { if (isset($join->alias)) { $orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to], $join->alias); } else { $orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to]); } } } elseif (isset($join->alias)) { $orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to], $join->alias); } else { $orm = $orm->{$method}($join->table, [$join->from, $join->operator, $join->to]); } } return $orm; } protected ?array $conditions; public function where(array $conditions): Model { foreach ($conditions as $condition) { $this->addCondition($condition); } return $this; } protected function addCondition(array $condition) { $map = [ 'column' => ['column', 'field', 'col', 'c', 'f', 0], 'value' => ['value', 'val', 'v', 1], 'operator' => ['operator', 'op', 'o', 'type', 't', 2] ]; $defaults = ['operator' => '=', 'type' => 'eq']; $required = ['column', 'value', 'operator']; $c = []; foreach ($condition as $key => $val) { $k = -1; foreach ($map as $i => $m) { if (is_array($m)) { if (in_array($key, $m)) { $k = $i; break; } continue; } if ($key == $m) { $k = $i; } } $c[$k] = $val; } foreach ($defaults as $key => $val) { if (!isset($c[$key])) { $c[$key] = $val; } } foreach ($required as $key) { if (!isset($c[$key])) { throw new InvalidArgumentException("Missing {$key} when adding conditions in " . get_class()); } } $this->conditions []= (object) $c; } protected function parseConditions(ORM $orm): ORM { if ($this->conditions === null) { return $orm; } foreach ($this->conditions as $condition) { $method = match(strtolower($condition->operator)) { '', '=', 'eq', 'equal', 'equals' => 'where', '<', 'lt', 'less than', 'less_than', 'lessthan' => 'whereLt', '<=', 'lte', 'less equal', 'less equals', 'less_equal', 'less_equals', 'lessequal', 'lessequals', 'less than equal', 'less than equals', 'less_than_equal', 'less_than_equals', 'lessthanequal', 'lessthanequals' => 'whereLte', '>', 'gt', 'greater than', 'greater_than', 'greaterthan' => 'whereGt', '>=', 'gte', 'greater equal', 'greater equals', 'greater_equal', 'greater_equals', 'greaterequal', 'greaterequals', 'greater than equal', 'greater than equals', 'greater_than_equal', 'greater_than_equals', 'greaterthanequal', 'greaterthanequals' => 'whereGte', '!=', 'not equal', 'not equals', 'not_equal', 'not_equals', 'notequal', 'notequals' => 'whereNotEqual', 'like' => 'whereLike', 'not like', 'not_like', 'notlike' => 'whereNotLike', 'in' => 'whereIn', 'not in', 'not_in', 'notin' => 'whereNotIn', 'raw' => 'raw' }; $orm = $orm->{$method}($condition->column, $condition->value); } return $orm; } protected ?array $groups; public function group($groups): Model { if (!is_array($groups)) { $groups = [$groups]; } foreach ($groups as $group) { $this->addGroup($group); } return $this; } protected function addGroup(string $group) { $this->groups []= $group; } protected function parseGroups(ORM $orm): ORM { if ($this->groups === null) { return $orm; } foreach ($this->groups as $group) { if (str_contains($group, '(')) { $orm = $orm->groupByExpr($group); continue; } $orm = $orm->groupBy($group); } return $orm; } protected ?array $orders; public function order($orders): Model { if (!is_array($orders)) { $orders = [$orders]; } foreach ($orders as $order) { $this->addOrder($order); } return $this; } protected function addOrder($order) { $map = [ 'column' => ['column', 'col', 'c', 0], 'direction' => ['direction', 'dir', 'd', 1] ]; if (!is_array($order)) { $order = [$order]; } $defaults = ['direction' => 'asc']; $required = ['column', 'direction']; $o = []; foreach ($order as $key => $val) { /*$k = match (strtolower($key)) { 'column', 'col', 'c', 0 => 'column', 'direction', 'dir', 'd', 1 => 'direction' };*/ $k = -1; foreach ($map as $i => $m) { if (is_array($m)) { if (in_array($key, $m)) { $k = $i; break; } continue; } if ($key == $m) { $k = $i; } } $o[$k] = $val; } foreach ($defaults as $key => $val) { if (!isset($o[$key])) { $o[$key] = $val; } } foreach ($required as $key) { if (!isset($o[$key])) { throw new InvalidArgumentException("Missing {$key} in order."); } } $this->orders []= (object) $o; } protected function parseOrders(ORM $orm): ORM { if ($this->orders === null) { return $orm; } foreach ($this->orders as $order) { if (str_contains($order->column, '(')) { $orm = $orm->orderByExpr($order->column); continue; } $method = match (strtolower($order->direction)) { 'ascending', 'asc', '' => 'orderByAsc', 'descending', 'desc' => 'orderByDesc' }; $orm = $orm->{$method}($order->column); } return $orm; } protected ?int $limit; public function limit(int $limit): Model { $this->limit = $limit; return $this; } protected function parseLimit(ORM $orm): ORM { if ($this->limit === null) { return $orm; } return $orm->limit($this->limit); } protected ?int $offset; public function offset(int $offset): Model { $this->offset = $offset; return $this; } protected function parseOffset(ORM $orm): ORM { if ($this->offset === null) { return $orm; } return $orm->offset($this->offset); } public function build(): ORM { $orm = BaseModel::factory($this->class); $methods = [ 'columns', 'joins', 'conditions', 'groups', 'orders', 'limit', 'offset' ]; foreach ($methods as $m) { $method = 'parse' . ucfirst($m); $orm = $this->{$method}($orm); } return $orm; } public function one(?int $id = null): bool|ModelInterface { $result = $this->build()->find_one($id); if ($result !== false) { $result->setFactory($this); } return $result; } public function many(): bool|array { $results = $this->build()->find_many(); if ($results !== false) { foreach ($results as &$result) { $result->setFactory($this); } } return $results; } public function array(): ?array { $results = $this->many(); if ($results === false) { return null; } return array_map(function($item) { return $item->toArray(); }, $results); } }