405 lines
11 KiB
PHP
405 lines
11 KiB
PHP
<?php
|
|
namespace Incoviba\API\Common\Factory;
|
|
|
|
use InvalidArgumentException;
|
|
use ORM;
|
|
use Incoviba\API\Common\Alias\Model as BaseModel;
|
|
use Incoviba\API\Common\Define\Model as ModelInterface;
|
|
|
|
class Model {
|
|
public static function for(string $class): Model {
|
|
$factory = new Model();
|
|
return $factory->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);
|
|
}
|
|
}
|