items = $items; if ($classname) { $this->classname = $classname; $this->id_lang = $id_lang; $this->definition = ObjectModel::getDefinition($this->classname); if (!isset($this->definition['table'])) { throw new Exception('Miss table in definition for class ' . $this->classname); } elseif (!isset($this->definition['primary'])) { throw new Exception('Miss primary in definition for class ' . $this->classname); } $this->query = new DbQuery(); } } /** * JOIN mit assoziierten Entitäten */ public function join($association, $on = '', $type = null) { if (!$association) { return $this; } if (!isset($this->join_list[$association])) { $definition = $this->getDefinition($association); $on = '{' . $definition['asso']['complete_field'] . '} = {' . $definition['asso']['complete_foreign_field'] . '}'; $type = self::LEFT_JOIN; $this->join_list[$association] = [ 'table' => ($definition['is_lang']) ? $definition['table'] . '_lang' : $definition['table'], 'alias' => $this->generateAlias($association), 'on' => [], ]; } if ($on) { $this->join_list[$association]['on'][] = $this->parseFields($on); } if ($type) { $this->join_list[$association]['type'] = $type; } return $this; } /** * WHERE-Bedingung (Vergleich) */ public function where($field, $operator, $value = null, $method = 'where') { if (func_num_args() == 2) { $value = $operator; $operator = '='; } if ($method != 'where' && $method != 'having') { throw new Exception('Bad method argument for where() method (should be "where" or "having")'); } // Array-Werte (IN, NOT IN) if (is_array($value)) { switch (strtolower($operator)) { case '=': case 'in': $this->query->$method($this->parseField($field) . ' IN(' . implode(', ', $this->formatValue($value, $field)) . ')'); break; case '!=': case '<>': case 'notin': $this->query->$method($this->parseField($field) . ' NOT IN(' . implode(', ', $this->formatValue($value, $field)) . ')'); break; default: throw new Exception('Operator not supported for array value'); } } else { // Einzelwerte switch (strtolower($operator)) { case '=': case '!=': case '<>': case '>': case '>=': case '<': case '<=': case 'like': case 'regexp': $this->query->$method($this->parseField($field) . ' ' . $operator . ' ' . $this->formatValue($value, $field)); break; case 'notlike': $this->query->$method($this->parseField($field) . ' NOT LIKE ' . $this->formatValue($value, $field)); break; case 'notregexp': $this->query->$method($this->parseField($field) . ' NOT REGEXP ' . $this->formatValue($value, $field)); break; default: throw new Exception('Operator not supported'); } } return $this; } /** * SQL WHERE mit direktem SQL */ public function sqlWhere($sql) { $this->query->where($this->parseFields($sql)); return $this; } /** * HAVING-Bedingung */ public function having($field, $operator, $value) { return $this->where($field, $operator, $value, 'having'); } /** * SQL HAVING mit direktem SQL */ public function sqlHaving($sql) { $this->query->having($this->parseFields($sql)); return $this; } /** * WHERE IN */ public function whereIn($key, array $values) { $filtered = array_filter($this->items, function ($item) use ($key, $values) { $itemValue = is_array($item) ? $item[$key] : $item->$key; return in_array($itemValue, $values); }); return new static(array_values($filtered)); } /** * WHERE BETWEEN */ public function whereBetween($key, array $range) { $filtered = array_filter($this->items, function ($item) use ($key, $range) { $itemValue = is_array($item) ? $item[$key] : $item->$key; return $itemValue >= $range[0] && $itemValue <= $range[1]; }); return new static(array_values($filtered)); } /** * WHERE NULL */ public function whereNull($key) { $filtered = array_filter($this->items, function ($item) use ($key) { $itemValue = is_array($item) ? $item[$key] : $item->$key; return is_null($itemValue); }); return new static(array_values($filtered)); } /** * WHERE NOT NULL */ public function whereNotNull($key) { $filtered = array_filter($this->items, function ($item) use ($key) { $itemValue = is_array($item) ? $item[$key] : $item->$key; return !is_null($itemValue); }); return new static(array_values($filtered)); } /** * ORDER BY */ public function orderBy($field, $order = 'asc') { if ($this->query) { $this->query->orderBy($this->parseField($field) . ' ' . strtoupper($order)); return $this; } $items = $this->items; usort($items, function ($a, $b) use ($field, $order) { $aValue = is_array($a) ? $a[$field] : $a->$field; $bValue = is_array($b) ? $b[$field] : $b->$field; $result = $aValue <=> $bValue; return $order === 'desc' ? -$result : $result; }); return new static($items); } /** * SQL ORDER BY */ public function sqlOrderBy($sql) { $this->query->orderBy($this->parseFields($sql)); return $this; } /** * ORDER BY DESC */ public function orderByDesc($key) { return $this->orderBy($key, 'desc'); } /** * GROUP BY */ public function groupBy($field) { $this->query->groupBy($this->parseField($field)); return $this; } /** * SQL GROUP BY */ public function sqlGroupBy($sql) { $this->query->groupBy($this->parseFields($sql)); return $this; } /** * Neueste zuerst (nach Feld, default: date_add) */ public function latest($key = 'date_add') { return $this->orderByDesc($key); } /** * Älteste zuerst (nach Feld, default: date_add) */ public function oldest($key = 'date_add') { return $this->orderBy($key); } /** * Alle Ergebnisse abrufen */ public function getAll($display_query = false) { if ($display_query) { echo $this->query->build(); } if (!$this->is_hydrated) { $this->results = Db::getInstance()->executeS($this->query->build()); $this->is_hydrated = true; } return $this->results; } /** * Erstes Element */ public function getFirst() { if (!$this->is_hydrated) { $this->getAll(); } return reset($this->results); } /** * Letztes Element */ public function getLast() { if (!$this->is_hydrated) { $this->getAll(); } return end($this->results); } /** * Ergebnisse abrufen */ public function getResults() { return $this->getAll(); } /** * Pagination */ public function paginate($perPage = 20, $page = 1) { $this->setPageSize($perPage); $this->setPageNumber($page); $offset = ($page - 1) * $perPage; $items = array_slice($this->items, $offset, $perPage); return new static($items); } /** * Einfache Pagination (liefert Array) */ public function simplePaginate($perPage = 20, $page = 1) { $offset = ($page - 1) * $perPage; return array_slice($this->items, $offset, $perPage); } /** * Chunk-Verarbeitung */ public function chunk($size, callable $callback) { $chunks = array_chunk($this->items, $size); foreach ($chunks as $chunk) { $callback(new static($chunk)); } } /** * Iterator (each) */ public function each(callable $callback) { foreach ($this->items as $key => $item) { $callback($item, $key); } return $this; } /** * Iterator-Methoden */ public function rewind(): void { $this->iterator = 0; $this->total = count($this->items); } public function current() { return $this->items[$this->iterator]; } public function valid(): bool { return $this->iterator < $this->total; } public function key() { return $this->iterator; } public function next(): void { ++$this->iterator; } /** * Zähle Elemente */ public function count(): int { return count($this->items); } /** * IteratorAggregate */ public function getIterator() { return new \ArrayIterator($this->items); } /** * ArrayAccess-Methoden */ public function offsetExists($offset): bool { return isset($this->items[$offset]); } public function offsetGet($offset) { return $this->items[$offset]; } public function offsetSet($offset, $value): void { if (is_null($offset)) { $this->items[] = $value; } else { $this->items[$offset] = $value; } } public function offsetUnset($offset): void { unset($this->items[$offset]); } /** * Alle Elemente als Array */ public function all() { return $this->items; } /** * Erstes Element */ public function first() { return reset($this->items); } /** * Letztes Element */ public function last() { return end($this->items); } /** * Leere Collection? */ public function isEmpty() { return empty($this->items); } /** * Definition abrufen */ protected function getDefinition($association) { if (!isset($this->association_definition[$association])) { $definition = ObjectModel::getDefinition($association); if (!isset($definition['associations'])) { throw new Exception('No associations found for ' . $association); } $this->association_definition[$association] = $definition; } return $this->association_definition[$association]; } /** * Felder parsen */ protected function parseFields($str) { return preg_replace_callback('/\{([^}]+)\}/', function ($matches) { return $this->parseField($matches[1]); }, $str); } /** * Feld parsen */ protected function parseField($field) { $field_info = $this->getFieldInfo($field); return $field_info['alias'] . '.' . $field_info['field']; } /** * Werte formatieren */ protected function formatValue($value, $field) { if (is_null($value)) { return 'NULL'; } if (is_bool($value)) { return $value ? '1' : '0'; } if (is_string($value)) { return "'" . pSQL($value) . "'"; } return $value; } /** * Feld-Informationen abrufen */ protected function getFieldInfo($field) { if (!isset($this->fields[$field])) { $this->fields[$field] = [ 'field' => $field, 'alias' => 'main' ]; } return $this->fields[$field]; } /** * Seitenzahl setzen */ public function setPageNumber($page_number) { $this->page_number = (int) $page_number; return $this; } /** * Seitengröße setzen */ public function setPageSize($page_size) { $this->page_size = (int) $page_size; return $this; } /** * Alias generieren */ protected function generateAlias($association = '') { return 'alias_' . ++$this->alias_iterator; } }