container = $container; } public function reset() { foreach ($this as $property => $value) { if ($property == 'container') { continue; } $this->$property = null; } } protected $class; public function find(string $model_class): Model { $this->reset(); if (!class_exists($model_class)) { throw new \InvalidArgumentException($model_class . ' not found.'); } $this->class = $model_class; return $this; } protected $columns; /** * , [, , ...] * string | array(array) * : [, *, *] */ public function select($columns): Model { if ($this->columns == null) { $this->columns = []; } if (!is_array($columns)) { $columns = [[$columns]]; } $this->columns = array_merge($this->columns, $columns); return $this; } protected function parseSelect(ORM $orm): ORM { if ($this->columns == null or count($this->columns) == 0) { return $orm; } foreach ($this->columns as $column) { if (is_string($column)) { $column = [$column]; } $value = $column[0]; $alias = $column['alias'] ?? $column[1] ?? ''; $method = 'select'; if (count($column) > 2 or isset($column['type'])) { $type = $column['type'] ?? $column[2] ?? ''; switch ($type) { case 'expr': $method .= 'Expr'; break; } } if ($alias == '') { $orm = $orm->{$method}($value); continue; } $orm = $orm->{$method}($value, $alias); } return $orm; } protected $joins; public function join(array $joins): Model { if ($this->joins == null) { $this->joins = []; } $this->joins = array_merge($this->joins, $joins); return $this; } public function parseJoin(ORM $orm): ORM { if ($this->joins == null or count($this->joins) == 0) { return $orm; } foreach ($this->joins as $join) { $method = 'join'; if (isset($join['type'])) { switch (strtolower($join['type'])) { case 'left': $method = 'leftOuterJoin'; break; case 'right': $method = 'rightOuterJoin'; break; case 'raw': $method = 'rawJoin'; break; } } $table = $join[0]; if (isset($join['table'])) { $table = $join['table']; } $field1 = $join[1]; if (isset($join['field1'])) { $field1 = $join['field1']; } $op = '='; if (isset($join['operator'])) { $op = $join['operator']; } $field2 = $join[2]; if (isset($join['field2'])) { $field2 = $join['field2']; } $alias = null; if (isset($join['alias'])) { $alias = $join['alias']; } $orm = $orm->{$method}($table, [$field1, $op, $field2], $alias); } return $orm; } protected $conditions; public function where(array $conditions): Model { if ($this->conditions == null) { $this->conditions = []; } foreach ($conditions as $condition) { $this->addCondition($condition); } return $this; } protected function addCondition(Condition $condition) { $this->conditions []= $condition; } protected function parseWhere(ORM $orm): ORM { if ($this->conditions == null or count($this->conditions) == 0) { return $orm; } foreach ($this->conditions as $condition) { $orm = $condition->build($orm); } return $orm; } protected $ordering; public function order($orders): Model { if ($this->ordering == null) { $this->ordering = []; } if (!is_array($orders)) { $orders = [$orders]; } $this->ordering = array_merge($this->ordering, $orders); return $this; } protected function parseOrder(ORM $orm): ORM { if ($this->ordering == null or count($this->ordering) == 0) { return $orm; } foreach ($this->ordering as $order => $dir) { if (is_numeric($order)) { $order = $dir; $dir = 'asc'; } $method = 'orderBy' . ucfirst(strtolower($dir)); $orm = $orm->{$method}($order); } return $orm; } protected $grouping; public function group($groups): Model { if ($this->grouping == null) { $this->grouping = []; } if (!is_array($groups)) { $groups = [$groups]; } $this->grouping = array_merge($this->grouping, $groups); return $this; } protected function parseGroup(ORM $orm): ORM { if ($this->grouping == null or count($this->grouping) == 0) { return $orm; } foreach ($this->grouping as $group) { $orm = $orm->groupBy($group); } return $orm; } protected $limits; public function limit(int $limit, int $offset = 0): Model { $this->limits = (object) ['limit' => $limit, 'offset' => $offset]; return $this; } protected function parseLimit(ORM $orm): ORM { if ($this->limits == null) { return $orm; } $orm = $orm->limit($this->limits->limit); if ($this->limits->offset > 0) { $orm = $orm->offset($this->limits->offset); } return $orm; } public function build(): ORM { $orm = BaseFactory::factory($this->class); $methods = ['select', 'join', 'where', 'order', 'group', 'limit']; foreach ($methods as $m) { $method = 'parse' . ucfirst($m); $orm = $this->{$method}($orm); } return $orm; } public function one($key = null) { $model = $this->build()->findOne($key); if ($model === false) { return false; } $model->setContainer($this->container); return $model; } public function many(): array { $models = $this->build()->findMany(); array_walk($models, function(&$item, $key, $container) { $item->setContainer($container); }, $this->container); return $models; } public function array(): array { $models = $this->many(); return array_map(function($item) { return $item->toArray(); }, $models); } public function create(string $model_class, array $data) { $factory = new Model($this->container); $where = []; foreach ($data as $column => $condition) { $where []= [$column, $condition]; } $obj = $factory->find($model_class)->where($where)->one(); if ($obj === false) { $obj = BaseFactory::factory($model_class)->create($data); $obj->save(); $obj->setContainer($this->container); } return $obj; } }