controller = $controller; } /** * Query Builder * @param string $table table name * @param string|null $as * @return QueryBuilder */ public function query($table, $as = null) { return $this->db->query($table, $as); } /** * Query Builder: Select * * $this->select(TABLE, [], 5); // SELECT * FROM TABLE WHERE id = 5 LIMIT 1 * $this->select(TABLE, ['id','title'], 10); // SELECT id, title FROM TABLE WHERE id = 10 LIMIT 1 * $this->select(TABLE.' as T', ['T.id','T.title'])->where('T.id', '>', 5)->get(); // SELECT T.id, T.title FROM TABLE as T WHERE T.id > 5 * * @param string|array $table table name * @param string|array|mixed $columns columns list * @param int|array|null $id row id * @param string $idKey id column name * @return QueryBuilder|Collection|mixed */ public function select($table, $columns = ['*'], $id = null, $idKey = 'id') { $query = $this->db->query($table); if (! is_null($id)) { if (is_array($id) || $id instanceof Arrayable) { return $query->whereIn($idKey, $id)->get($columns)->keyBy($idKey); } else { return $query->where($idKey, '=', $id)->first($columns); } } return $query->select($columns); } /** * Query Builder: Update * * $this->update(TABLE, ['title'=>'John'], 1); // UPDATE TABLE SET title = "John" WHERE id = 1 * * @param string $table table name * @param array $values set values * @param int|array $id row id * @param string $idKey id column name * @return mixed */ public function update($table, array $values, $id, $idKey = 'id') { $query = $this->db->query($table); if (is_array($id) || $id instanceof Arrayable) { $query->whereIn($idKey, $id); } else { $query->where($idKey, '=', $id); } return $query->update($values); } /** * Query Builder: Insert * * $this->insert(TABLE, ['title'=>'Max','enabled'=>1]); * * @param string $table table name * @param array $values values to insert * @param bool|string|null $getId return last inserted row id * @return mixed */ public function insert($table, array $values = [], $getId = true) { $query = $this->db->query($table); if (! empty($returnId)) { return $query->insertGetId($values, $getId); } return $query->insert($values); } /** * Query Builder: Delete * * $this->delete(TABLE, 10); // DELETE FROM TABLE WHERE id = 10 * * @param string $table table name * @param int|null $id delete row by id * @param string $idKey id column name * @return int rows deleted */ public function delete($table, $id, $idKey = 'id') { return $this->db->query($table)->where($idKey, $id)->delete(); } /** * Get rows list * @param string $table * @param array|mixed $where * @param array $columns * @param string $orderBy * @param int $limit * @param int $offset * @deprecated * @return array */ public function getList($table, $where, $columns = ['*'], $orderBy = '', $limit = 0, $offset = 0) { return $this->query($table)->select($columns)->where($where) ->when($orderBy, function ($q, $orderBy) { $q->orderBy($orderBy); }) ->when($limit, function ($q, $limit) { $q->limit($limit); }) ->when($offset, function ($q, $offset) { $q->offset($offset); }) ->get()->toArray(); } /** * Get list rows count * @param string $table * @param mixed $where * @deprecated * @return int */ public function getListCount($table, $where) { return $this->query($table)->select()->where($where)->count(); } public function findOne($table, $where, $fields = ['*'], $orderBy = '') { if (is_numeric($where)) { $where = ['id' => $where]; } return $this->db->select_row($table, $fields, $where, $orderBy); } public function findMany($table, $where, $fields = ['*'], $orderBy = '', $limit = '') { return $this->db->select_rows($table, $fields, $where, $orderBy, $limit); } /** * Current date & time * @param bool $quote * @return string */ public function now($quote = false) { return $this->db->now($quote); } /** * Get model class name * @param string $modelName model name * @param string|null $moduleName module name * @param bool $asObject * @return \bff\db\illuminate\Model|string */ public function model($modelName, $moduleName = null, $asObject = true) { if (is_null($moduleName)) { if ($this->controller instanceof Module) { $moduleName = $this->controller->module_name; } else { $moduleName = $this->controller; } } return bff::model($moduleName, $modelName, !$asObject); } /** * Проверка на соответствие оператору сравнения * @param mixed $value * @return bool */ public static function isOperator($value) { return (is_string($value) && !empty($value) && in_array(mb_strtoupper($value), [ '=', '<', '>', '<=', '>=', '<>', '!=', '<=>', '&', '|', '^', '<<', '>>', '~', 'IN', 'NOT IN', 'LIKE', 'LIKE BINARY', 'NOT LIKE', 'ILIKE', 'NOT ILIKE', 'RLIKE', 'REGEXP', 'NOT REGEXP', ], true)); } /** * Построение условия сравнения для указанной колонки * @param string $columnName название колонки * @param $value: 'int|string', [1,2,3,...], ['>=', 'value'], ['in', [1,2,3]] * @param array $bind @ref * @param string $prefix * @return string */ public static function condition($columnName, $value, array &$bind = [], $prefix = '') { $operator = '='; if (is_array($value)) { $operator = 'IN'; if (sizeof($value) == 2 && static::isOperator(current($value))) { $operator = mb_strtoupper(array_shift($value)); $value = reset($value); } if ($operator === 'IN' || $operator === 'NOT IN') { return bff::database()->prepareIN($prefix . $columnName, $value, ($operator === 'NOT IN')); } } $bindKey = ':' . $columnName; while (isset($bind[$bindKey])) { $bindKey .= 'A'; } $bind[$bindKey] = $value; return $prefix . bff::database()->wrapColumn($columnName) . ' ' . $operator . ' ' . $bindKey; } /** * Quote column name * @param string|array $column * @return string|array */ public function wrapColumn($column) { return $this->db->wrapColumn($column); } /** * Строит IN или NOT IN sql строку сравнения * @param string $column название колонки для сравнения * @param array $values массив значений - разрешенных (IN) или запрещенных (NOT IN) * @param bool $not true: NOT IN (), false: IN () * @param bool $allowEmptySet true - разрешить массив $aValues быть пустым, эта функция вернет 1=1 или 1=0 * @param bool $ints приводит значения к int * @return mixed */ public function prepareIN(string $column, array $values, bool $not = false, bool $allowEmptySet = true, ?bool $ints = null) { return $this->db->prepareIN($column, $values, $not, $allowEmptySet, $ints); } /** * Формируем SQL-фильтр @see static::filter * @param array $filter параметры * @param string|bool $prefix префикс * @param array $bind данные для биндинга * @return array */ public function prepareFilter(array $filter = [], $prefix = '', array $bind = []) { return static::filter($filter, $prefix, $bind); } /** * Формируем SQL-фильтр запроса * @param array $filter параметры, @examples: * $filter['status'] = 7; (prefix+) * $filter[':status'] = '(status IN (1,2,3))'; (as is) * $filter[':status'] = array('(status >= :min OR status <= :max)', ':min'=>1, ':max'=>3); (as is + bind) * $filter[] = 'status IS NOT NULL'; (prefix+) * $filter[] = array('title LIKE :title', ':title'=>'Super Title'); (as is + bind) * @param string|bool $prefix префикс * @param array $bind данные для биндинга * @return array ('where'=>string,'bind'=>array|NULL) */ public static function filter(array $filter = [], $prefix = '', array $bind = []) { $prefix = (!empty($prefix) ? $prefix . '.' : ''); $where = []; foreach ($filter as $key => $val) { if (is_int($key)) { if (is_string($val)) { ## filter[] = 'status IS NOT NULL'; $where[] = $prefix . $val; } else { if (is_array($val) && sizeof($val) >= 2) { // condition + binds ## filter[] = array('num > :x', ':x'=>9) $where[] = array_shift($val); foreach ($val as $k => $v) { $bind[$k] = $v; } } } } elseif (is_string($key)) { if ($key[0] == ':') { if (is_string($val)) { // condition ## filter[:range] = '(total > 0 OR total < 10)' $where[] = $val; } elseif (is_array($val) && sizeof($val) >= 2) { // one condition + binds ## filter[:num] = array('num > :x', ':x'=>9) $where[] = array_shift($val); foreach ($val as $k => $v) { $bind[$k] = $v; } } } else { ## filter['status'] = 7; ## filter['id'] = [1,2,3]; => id IN (1,2,3) ## filter['id'] = ['>=',5]; => id >= 5 ## filter['id'] = ['LIKE','string%']; => id LIKE 'string%' $where[] = static::condition($key, $val, $bind, $prefix); } } } return [ 'where' => (!empty($where) ? ' WHERE ' . join(' AND ', $where) . ' ' : ' '), 'bind' => (!empty($bind) ? $bind : null), ]; } /** * Инвертирование поля типа "enabled" * @param string $table таблица * @param int $recordID ID записи * @param string $fieldToggle название поля "enabled" * @param string $fieldID название поля "id" * @param bool $withRotation учитывать ротацию по полю "enabled" * @return mixed */ public function toggleInt($table, $recordID, $fieldToggle = 'enabled', $fieldID = 'id', $withRotation = false) { if ($withRotation) { $aData = $this->db->one_array("SELECT $fieldToggle FROM $table WHERE $fieldID = :id", [':id' => $recordID]); if (empty($aData[$fieldToggle])) { $nMax = (int)$this->db->one_data("SELECT MAX($fieldToggle) FROM $table"); return $this->db->update($table, [$fieldToggle => $nMax + 1], "$fieldID = :id", [':id' => $recordID]); } else { return $this->db->exec("UPDATE $table SET $fieldToggle = 0 WHERE $fieldID = :id", [':id' => $recordID]); } } else { if (is_array($recordID)) { return $this->db->update($table, ["$fieldToggle = (1 - $fieldToggle)"], [$fieldID => $recordID]); } else { return $this->db->exec("UPDATE $table SET $fieldToggle = (1 - $fieldToggle) WHERE $fieldID = :id", [':id' => $recordID]); } } } /** * Выделение полей из списка в флаги * @param array $fields @ref массив полей, может быть в формате array('field', 'flag'=> array('f1', 'f2')), если array, то flag будет не true а array('f1', 'f2') * @param array $keys какие поля перенести в флаги, * формат array('field', 'field' => 'new field', 'field' => array('new field1', 'new field2')), * если 'field' => 'new field' - замена имени, если 'field' => array(...) - добавление всех полей из массива * @param string $prefix * @param string|array $check_ID добавить поле $check_ID или поля из массива($check_ID) в $fields, если его нет * @return array массив флагов */ public function prepareFields(&$fields, array $keys = [], $prefix = '', $check_ID = 'id') { $result = []; if (empty($fields)) { # для пустого массива все флаги - в true foreach ($keys as $k => $v) { if (is_int($k)) { $result[$v] = true; } else { $result[$k] = true; } } $fields[] = '*'; return $result; } # для возможного изменения в результате с true на array(...) $resultFields = []; foreach ($fields as $k => $v) { if (is_string($k) && is_array($v)) { $resultFields[$k] = $v; unset($fields[$k]); } } foreach ($resultFields as $k => $v) { if (! array_search($k, $fields)) { $fields[] = $k; } } foreach ($keys as $k => $v) { if (is_int($k)) { $key = array_search($v, $fields, true); if ($key !== false) { $result[$v] = true; unset($fields[$key]); } else { $result[$v] = false; } } else { $key = array_search($k, $fields, true); if ($key !== false) { unset($fields[$key]); $result[$k] = true; $addFields = is_array($v) ? $v : [$v]; foreach ($addFields as $f) { if (! in_array($f, $fields, true)) { $fields[] = $f; } } } else { $result[$k] = false; } } } # заменим результат с true на array(...) if (! empty($resultFields)) { foreach ($result as $k => $v) { if ($v && isset($resultFields[$k])) { $result[$k] = $resultFields[$k]; } } } # проверим $check_ID if (! empty($check_ID)) { if (! is_array($check_ID)) { $check_ID = array($check_ID); } foreach ($check_ID as $v) { if (! in_array($v, $fields)) { $fields[] = $v; } } } # append prefix if (! empty($prefix)) { $prefix = $prefix . '.'; foreach ($fields as &$v) { $pos = strpos($v, '.'); if ($pos === false) { $v = $prefix . $v; } } unset($v); } # replace {lng} $lng = $this->locale->getCurrentLanguage(); foreach ($fields as & $v) { $v = str_replace('{lng}', $lng, $v); } unset($v); return $result; } }