![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/ledger.corals.io/Corals/core/Foundation/DataTables/QueryBuilderParser/ |
<?php namespace Corals\Foundation\DataTables\QueryBuilderParser; use Carbon\Carbon; use Corals\Foundation\DataTables\QueryBuilderParser\Exceptions\QBParseException; use Corals\Foundation\DataTables\QueryBuilderParser\Exceptions\QBRuleException; use Illuminate\Database\Eloquent\Builder; use stdClass; trait QBPFunctions { /** * @param stdClass $rule */ abstract protected function checkRuleCorrect(stdClass $rule); protected $operators = array( 'equal' => array('accept_values' => true, 'apply_to' => ['string', 'number', 'datetime']), 'not_equal' => array('accept_values' => true, 'apply_to' => ['string', 'number', 'datetime']), 'in' => array('accept_values' => true, 'apply_to' => ['string', 'number', 'datetime']), 'not_in' => array('accept_values' => true, 'apply_to' => ['string', 'number', 'datetime']), 'less' => array('accept_values' => true, 'apply_to' => ['number', 'datetime']), 'less_or_equal' => array('accept_values' => true, 'apply_to' => ['number', 'datetime']), 'greater' => array('accept_values' => true, 'apply_to' => ['number', 'datetime']), 'greater_or_equal' => array('accept_values' => true, 'apply_to' => ['number', 'datetime']), 'between' => array('accept_values' => true, 'apply_to' => ['number', 'datetime']), 'not_between' => array('accept_values' => true, 'apply_to' => ['number', 'datetime']), 'begins_with' => array('accept_values' => true, 'apply_to' => ['string']), 'not_begins_with' => array('accept_values' => true, 'apply_to' => ['string']), 'contains' => array('accept_values' => true, 'apply_to' => ['string']), 'not_contains' => array('accept_values' => true, 'apply_to' => ['string']), 'ends_with' => array('accept_values' => true, 'apply_to' => ['string']), 'not_ends_with' => array('accept_values' => true, 'apply_to' => ['string']), 'is_empty' => array('accept_values' => false, 'apply_to' => ['string']), 'is_not_empty' => array('accept_values' => false, 'apply_to' => ['string']), 'is_null' => array('accept_values' => false, 'apply_to' => ['string', 'number', 'datetime']), 'is_not_null' => array('accept_values' => false, 'apply_to' => ['string', 'number', 'datetime']) ); protected $operator_sql = array( 'equal' => array('operator' => '='), 'not_equal' => array('operator' => '!='), 'in' => array('operator' => 'IN'), 'not_in' => array('operator' => 'NOT IN'), 'less' => array('operator' => '<'), 'less_or_equal' => array('operator' => '<='), 'greater' => array('operator' => '>'), 'greater_or_equal' => array('operator' => '>='), 'between' => array('operator' => 'BETWEEN'), 'not_between' => array('operator' => 'NOT BETWEEN'), 'begins_with' => array('operator' => 'LIKE', 'prepend' => '%'), 'not_begins_with' => array('operator' => 'NOT LIKE', 'prepend' => '%'), 'contains' => array('operator' => 'LIKE', 'append' => '%', 'prepend' => '%'), 'not_contains' => array('operator' => 'NOT LIKE', 'append' => '%', 'prepend' => '%'), 'ends_with' => array('operator' => 'LIKE', 'append' => '%'), 'not_ends_with' => array('operator' => 'NOT LIKE', 'append' => '%'), 'is_empty' => array('operator' => '='), 'is_not_empty' => array('operator' => '!='), 'is_null' => array('operator' => 'NULL'), 'is_not_null' => array('operator' => 'NOT NULL') ); protected $needs_array = array( 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', ); /** * Determine if an operator (LIKE/IN) requires an array. * * @param $operator * * @return bool */ protected function operatorRequiresArray($operator) { return in_array($operator, $this->needs_array); } /** * Determine if an operator is NULL/NOT NULL * * @param $operator * * @return bool */ protected function operatorIsNull($operator) { return ($operator == 'NULL' || $operator == 'NOT NULL') ? true : false; } /** * Make sure that a condition is either 'or' or 'and'. * * @param $condition * @return string * @throws QBParseException */ protected function validateCondition($condition) { $condition = trim(strtolower($condition)); if ($condition !== 'and' && $condition !== 'or') { throw new QBParseException("Condition can only be one of: 'and', 'or'."); } return $condition; } /** * Enforce whether the value for a given field is the correct type * * @param bool $requireArray value must be an array * @param mixed $value the value we are checking against * @param string $field the field that we are enforcing * @return mixed value after enforcement * @throws QBParseException if value is not a correct type */ protected function enforceArrayOrString($requireArray, $value, $field) { $this->checkFieldIsAnArray($requireArray, $value, $field); if (!$requireArray && is_array($value)) { return $this->convertArrayToFlatValue($field, $value); } return $value; } /** * Ensure that a given field is an array if required. * * @param boolean $requireArray * @param $value * @param string $field * @throws QBParseException * @see enforceArrayOrString */ protected function checkFieldIsAnArray($requireArray, $value, $field) { if ($requireArray && !is_array($value)) { throw new QBParseException("Field ($field) should be an array, but it isn't."); } } /** * Convert an array with just one item to a string. * * In some instances, and array may be given when we want a string. * * @param string $field * @param $value * @return mixed * @throws QBParseException * @see enforceArrayOrString */ protected function convertArrayToFlatValue($field, $value) { if (count($value) !== 1) { throw new QBParseException("Field ($field) should not be an array, but it is."); } return $value[0]; } /** * Convert a Datetime field to Carbon items to be used for comparisons. * * @param $value * @return \Carbon\Carbon * @throws QBParseException */ protected function convertDatetimeToCarbon($value) { if (is_array($value)) { return array_map(function ($v) { return new Carbon($v); }, $value); } return new Carbon($value); } /** * Append or prepend a string to the query if required. * * @param bool $requireArray value must be an array * @param mixed $value the value we are checking against * @param mixed $sqlOperator * @return mixed $value */ protected function appendOperatorIfRequired($requireArray, $value, $sqlOperator) { if (!$requireArray) { if (isset($sqlOperator['append'])) { $value = $sqlOperator['append'] . $value; } if (isset($sqlOperator['prepend'])) { $value = $value . $sqlOperator['prepend']; } } return $value; } /** * Decode the given JSON * * @param string incoming json * @return stdClass * @throws QBParseException */ private function decodeJSON($json) { $query = json_decode($json); if (json_last_error()) { throw new QBParseException('JSON parsing threw an error: ' . json_last_error_msg()); } if (!is_object($query)) { throw new QBParseException('The query is not valid JSON'); } return $query; } /** * get a value for a given rule. * * throws an exception if the rule is not correct. * * @param stdClass $rule * @throws QBRuleException */ private function getRuleValue(stdClass $rule) { if (!$this->checkRuleCorrect($rule)) { throw new QBRuleException(); } return $rule->value; } /** * Check that a given field is in the allowed list if set. * * @param $fields * @param $field * @throws QBParseException */ private function ensureFieldIsAllowed($fields, $field) { if (is_array($fields) && !in_array($field, $fields)) { throw new QBParseException("Field ({$field}) does not exist in fields list"); } } /** * makeQuery, for arrays. * * Some types of SQL Operators (ie, those that deal with lists/arrays) have specific requirements. * This function enforces those requirements. * * @param Builder $query * @param stdClass $rule * @param array $sqlOperator * @param array $value * @param string $condition * * @return Builder * @throws QBParseException * */ protected function makeQueryWhenArray($query, stdClass $rule, array $sqlOperator, array $value, $condition) { if ($sqlOperator['operator'] == 'IN' || $sqlOperator['operator'] == 'NOT IN') { return $this->makeArrayQueryIn($query, $rule, $sqlOperator['operator'], $value, $condition); } elseif ($sqlOperator['operator'] == 'BETWEEN' || $sqlOperator['operator'] == 'NOT BETWEEN') { return $this->makeArrayQueryBetween($query, $rule, $sqlOperator['operator'], $value, $condition); } throw new QBParseException('makeQueryWhenArray could not return a value'); } /** * Create a 'null' query when required. * * @param Builder $query * @param stdClass $rule * @param array $sqlOperator * @param string $condition * * @return Builder * @throws QBParseException when SQL operator is !null */ protected function makeQueryWhenNull($query, stdClass $rule, array $sqlOperator, $condition) { if ($sqlOperator['operator'] == 'NULL') { return $this->buildQuery($query, 'whereNull', $rule->field, $condition, $sqlOperator['operator']); } elseif ($sqlOperator['operator'] == 'NOT NULL') { return $this->buildQuery($query, 'whereNotNull', $rule->field, $condition, $sqlOperator['operator']); } throw new QBParseException('makeQueryWhenNull was called on an SQL operator that is not null'); } /** * makeArrayQueryIn, when the query is an IN or NOT IN... * * @param Builder $query * @param stdClass $rule * @param string $operator * @param array $value * @param string $condition * @return Builder * @see makeQueryWhenArray */ private function makeArrayQueryIn($query, stdClass $rule, $operator, array $value, $condition) { if ($operator == 'NOT IN') { return $this->buildQuery($query, 'whereNotIn', $rule->field, $condition, $operator, $value); } return $this->buildQuery($query, 'whereIn', $rule->field, $condition, $operator, $value); } /** * makeArrayQueryBetween, when the query is a BETWEEN or NOT BETWEEN... * * @param Builder $query * @param stdClass $rule * @param string operator the SQL operator used. [BETWEEN|NOT BETWEEN] * @param array $value * @param string $condition * @return Builder * @throws QBParseException when more then two items given for the between * @see makeQueryWhenArray */ private function makeArrayQueryBetween($query, stdClass $rule, $operator, array $value, $condition) { if (count($value) !== 2) { throw new QBParseException("{$rule->field} should be an array with only two items."); } if ($operator == 'NOT BETWEEN') { return $this->buildQuery($query, 'whereNotBetween', $rule->field, $condition, $operator, $value); } return $this->buildQuery($query, 'whereBetween', $rule->field, $condition, $operator, $value); } /** * @param $query * @param $queryMethod * @param $field * @param $condition * @param $operator * @param null $value * @return mixed|void */ protected function buildQuery($query, $queryMethod, $field, $condition, $operator, $value = null) { if (data_get($this->currentFilterAttributes, 'is_morph', false)) { $morphTypes = $this->currentFilterAttributes['morph_types']; $morphColumn = $this->currentFilterAttributes['morph_column']; return $this->buildMorphQuery($query, $morphColumn, $morphTypes, $queryMethod, $field, $condition, $operator, $value); } if (strpos($field, '.')) { list($relation, $column) = explode('.', $field); return $this->buildRelationalQuery($query, $relation, $queryMethod, $condition, $operator, $column, $value); } return $this->query($query, $queryMethod, $field, $condition, $operator, $value); } /** * @param $query * @param $relation * @param $queryMethod * @param $condition * @param $operator * @param $column * @param $value * @return mixed */ protected function buildRelationalQuery($query, $relation, $queryMethod, $condition, $operator, $column, $value) { if ($relation && method_exists($query->getModel(), $relation)) { return $query->has($relation, '>=', 1, $condition, function ($relQuery) use ($queryMethod, $condition, $column, $value, $relation, $operator) { $relationBaseTable = $relQuery->getModel()->getTable(); return $this->query($relQuery, $queryMethod, "$relationBaseTable.$column", 'AND', $operator, $value); }); } } /** * @param $query * @param $morphColumn * @param $morphTypes * @param $queryMethod * @param $column * @param $operator * @param $condition * @param $value * @return mixed */ protected function buildMorphQuery($query, $morphColumn, $morphTypes, $queryMethod, $column, $operator, $condition, $value) { return $query->whereHasMorph($morphColumn, $morphTypes, function ($query) use ($queryMethod, $column, $condition, $value, $operator) { $relationBaseTable = $query->getModel()->getTable(); return $this->query($query, $queryMethod, "$relationBaseTable.$column", $operator, $condition, $value); }); } /** * @param $query * @param $queryMethod * @param $field * @param $queryCondition * @param $operator * @param null $value * @return mixed */ protected function query($query, $queryMethod, $field, $queryCondition, $operator, $value = null) { if (in_array($queryMethod, ['whereBetween', 'whereNotBetween', 'whereNotIn', 'whereIn'])) { return $query->{$queryMethod}($field, $value, $queryCondition); } elseif (in_array($queryMethod, ['whereNotNull', 'whereNull'])) { return $query->{$queryMethod}($field, $queryCondition); } return $query->{$queryMethod}($field, $operator, $value, $queryCondition); } }