<commit_before><?php
/**
 * Created for someline-starter.
 * User: Libern
 */

namespace Someline\Repositories\Criteria;


use Prettus\Repository\Contracts\CriteriaInterface;
use Prettus\Repository\Contracts\RepositoryInterface;

class RequestCriteria extends \Prettus\Repository\Criteria\RequestCriteria
{

    /**
     * Apply criteria in query repository
     *
     * @param         Builder|Model $model
     * @param RepositoryInterface $repository
     *
     * @return mixed
     * @throws \Exception
     */
    public function apply($model, RepositoryInterface $repository)
    {
        $fieldsSearchable = $repository->getFieldsSearchable();
        $search = $this->request->get(config('repository.criteria.params.search', 'search'), null);
        $searchFields = $this->request->get(config('repository.criteria.params.searchFields', 'searchFields'), null);
        $filter = $this->request->get(config('repository.criteria.params.filter', 'filter'), null);
        $orderBy = $this->request->get(config('repository.criteria.params.orderBy', 'orderBy'), null);
        $sortedBy = $this->request->get(config('repository.criteria.params.sortedBy', 'sortedBy'), 'asc');
        $with = $this->request->get(config('repository.criteria.params.with', 'with'), null);
        $sortedBy = !empty($sortedBy) ? $sortedBy : 'asc';

        if ($search && is_array($fieldsSearchable) && count($fieldsSearchable)) {

            $searchFields = is_array($searchFields) || is_null($searchFields) ? $searchFields : explode(';', $searchFields);
            $fields = $this->parserFieldsSearch($fieldsSearchable, $searchFields);
            $isFirstField = true;
            $searchData = $this->parserSearchData($search);
            $search = $this->parserSearchValue($search);
            $modelForceAndWhere = method_exists($repository, 'getIsSearchableForceAndWhere') ? $repository->getIsSearchableForceAndWhere() : false;

            $model = $model->where(function ($query) use ($fields, $search, $searchData, $isFirstField, $modelForceAndWhere) {
                /** @var Builder $query */

                foreach ($fields as $field => $condition) {

                    if (is_numeric($field)) {
                        $field = $condition;
                        $condition = "=";
                    }

                    $value = null;

                    $condition = trim(strtolower($condition));

                    if (isset($searchData[$field])) {
                        if ($condition == "like_raw") {
                            $condition = "like";
                            $value = $searchData[$field];
                        } else if ($condition == "like_safe") {
                            $condition = "like";
                            if (str_contains_ascii_only($searchData[$field])) {
                                $value = "%{$searchData[$field]}%";
                            } else {
                                $value = null;
                            }
                        } else {
                            $value = ($condition == "like" || $condition == "ilike") ? "%{$searchData[$field]}%" : $searchData[$field];
                        }
                    } else {
                        if (!is_null($search)) {
                            if ($condition == "like_raw") {
                                $condition = "like";
                                $value = $searchData[$field];
                            } else if ($condition == "like_safe") {
                                $condition = "like";
                                if (str_contains_ascii_only($search)) {
                                    $value = "%{$search}%";
                                } else {
                                    $value = null;
                                }
                            } else {
                                $value = ($condition == "like" || $condition == "ilike") ? "%{$search}%" : $search;
                            }
                        }
                    }

                    $relation = null;
                    if (stripos($field, '.')) {
                        $explode = explode('.', $field);
                        $field = array_pop($explode);
                        $relation = implode('.', $explode);
                    }
                    $modelTableName = $query->getModel()->getTable();
                    if ($isFirstField || $modelForceAndWhere) {
                        if (!is_null($value)) {
                            if (!is_null($relation)) {
                                $query->whereHas($relation, function ($query) use ($field, $condition, $value) {
                                    $query->where($field, $condition, $value);
                                });
                            } else {
                                $query->where($modelTableName . '.' . $field, $condition, $value);
                            }
                            $isFirstField = false;
                        }
                    } else {
                        if (!is_null($value)) {
                            if (!is_null($relation)) {
                                $query->orWhereHas($relation, function ($query) use ($field, $condition, $value) {
                                    $query->where($field, $condition, $value);
                                });
                            } else {
                                $query->orWhere($modelTableName . '.' . $field, $condition, $value);
                            }
                        }
                    }
                }
            });
        }

        if (isset($orderBy) && !empty($orderBy)) {
            $split = explode('|', $orderBy);
            if (count($split) > 1) {
                /*
                 * ex.
                 * products|description -> join products on current_table.product_id = products.id order by description
                 *
                 * products:custom_id|products.description -> join products on current_table.custom_id = products.id order
                 * by products.description (in case both tables have same column name)
                 */
                $table = $model->getModel()->getTable();
                $sortTable = $split[0];
                $sortColumn = $split[1];

                $split = explode(':', $sortTable);
                if (count($split) > 1) {
                    $sortTable = $split[0];
                    $keyName = $table . '.' . $split[1];
                } else {
                    /*
                     * If you do not define which column to use as a joining column on current table, it will
                     * use a singular of a join table appended with _id
                     *
                     * ex.
                     * products -> product_id
                     */
                    $prefix = rtrim($sortTable, 's');
                    $keyName = $table . '.' . $prefix . '_id';
                }

                $model = $model
                    ->leftJoin($sortTable, $keyName, '=', $sortTable . '.id')
                    ->orderBy($sortColumn, $sortedBy)
                    ->addSelect($table . '.*');
            } else {
                $model = $model->orderBy($orderBy, $sortedBy);
            }
        }<commit_msg>Improved request criteria orderBy support<commit_after><?php
/**
 * Created for someline-starter.
 * User: Libern
 */

namespace Someline\Repositories\Criteria;


use Prettus\Repository\Contracts\CriteriaInterface;
use Prettus\Repository\Contracts\RepositoryInterface;

class RequestCriteria extends \Prettus\Repository\Criteria\RequestCriteria
{

    /**
     * Apply criteria in query repository
     *
     * @param         Builder|Model $model
     * @param RepositoryInterface $repository
     *
     * @return mixed
     * @throws \Exception
     */
    public function apply($model, RepositoryInterface $repository)
    {
        $fieldsSearchable = $repository->getFieldsSearchable();
        $search = $this->request->get(config('repository.criteria.params.search', 'search'), null);
        $searchFields = $this->request->get(config('repository.criteria.params.searchFields', 'searchFields'), null);
        $filter = $this->request->get(config('repository.criteria.params.filter', 'filter'), null);
        $orderBy = $this->request->get(config('repository.criteria.params.orderBy', 'orderBy'), null);
        $sortedBy = $this->request->get(config('repository.criteria.params.sortedBy', 'sortedBy'), 'asc');
        $with = $this->request->get(config('repository.criteria.params.with', 'with'), null);
        $sortedBy = !empty($sortedBy) ? $sortedBy : 'asc';

        if ($search && is_array($fieldsSearchable) && count($fieldsSearchable)) {

            $searchFields = is_array($searchFields) || is_null($searchFields) ? $searchFields : explode(';', $searchFields);
            $fields = $this->parserFieldsSearch($fieldsSearchable, $searchFields);
            $isFirstField = true;
            $searchData = $this->parserSearchData($search);
            $search = $this->parserSearchValue($search);
            $modelForceAndWhere = method_exists($repository, 'getIsSearchableForceAndWhere') ? $repository->getIsSearchableForceAndWhere() : false;

            $model = $model->where(function ($query) use ($fields, $search, $searchData, $isFirstField, $modelForceAndWhere) {
                /** @var Builder $query */

                foreach ($fields as $field => $condition) {

                    if (is_numeric($field)) {
                        $field = $condition;
                        $condition = "=";
                    }

                    $value = null;

                    $condition = trim(strtolower($condition));

                    if (isset($searchData[$field])) {
                        if ($condition == "like_raw") {
                            $condition = "like";
                            $value = $searchData[$field];
                        } else if ($condition == "like_safe") {
                            $condition = "like";
                            if (str_contains_ascii_only($searchData[$field])) {
                                $value = "%{$searchData[$field]}%";
                            } else {
                                $value = null;
                            }
                        } else {
                            $value = ($condition == "like" || $condition == "ilike") ? "%{$searchData[$field]}%" : $searchData[$field];
                        }
                    } else {
                        if (!is_null($search)) {
                            if ($condition == "like_raw") {
                                $condition = "like";
                                $value = $searchData[$field];
                            } else if ($condition == "like_safe") {
                                $condition = "like";
                                if (str_contains_ascii_only($search)) {
                                    $value = "%{$search}%";
                                } else {
                                    $value = null;
                                }
                            } else {
                                $value = ($condition == "like" || $condition == "ilike") ? "%{$search}%" : $search;
                            }
                        }
                    }

                    $relation = null;
                    if (stripos($field, '.')) {
                        $explode = explode('.', $field);
                        $field = array_pop($explode);
                        $relation = implode('.', $explode);
                    }
                    $modelTableName = $query->getModel()->getTable();
                    if ($isFirstField || $modelForceAndWhere) {
                        if (!is_null($value)) {
                            if (!is_null($relation)) {
                                $query->whereHas($relation, function ($query) use ($field, $condition, $value) {
                                    $query->where($field, $condition, $value);
                                });
                            } else {
                                $query->where($modelTableName . '.' . $field, $condition, $value);
                            }
                            $isFirstField = false;
                        }
                    } else {
                        if (!is_null($value)) {
                            if (!is_null($relation)) {
                                $query->orWhereHas($relation, function ($query) use ($field, $condition, $value) {
                                    $query->where($field, $condition, $value);
                                });
                            } else {
                                $query->orWhere($modelTableName . '.' . $field, $condition, $value);
                            }
                        }
                    }
                }
            });
        }

        if (isset($orderBy) && !empty($orderBy)) {
            $orderBys = explode(';', $orderBy); // products:product_id:product_id|products.name;updated_at,desc
            $originSortedBy = $sortedBy;
            foreach ($orderBys as $orderBy) {
                // split sorted by
                $splitSortedBy = explode(',', $orderBy);
                if (count($splitSortedBy) > 1) {
                    $sortedBy = $splitSortedBy[1];
                } else {
                    $sortedBy = $originSortedBy;
                }
                $orderBy = $splitSortedBy[0];

                // split joint
                $split = explode('|', $orderBy);
                if (count($split) > 1) {
                    /*
                     * ex.
                     * products|description -> join products on current_table.product_id = products.id order by description
                     *
                     * products:custom_id|products.description -> join products on current_table.custom_id = products.id order
                     * by products.description (in case both tables have same column name)
                     */
                    $table = $model->getModel()->getTable();
                    $sortTable = $split[0];
                    $sortColumn = $split[1];

                    $sortTableKeyName = 'id';
                    $split = explode(':', $sortTable);
                    if (count($split) > 2) { //    products:custom_id:products_table_custom_id|products.description
                        $sortTable = $split[0];
                        $keyName = $table . '.' . $split[1];
                        $sortTableKeyName = $split[2];
                    } else if (count($split) > 1) {
                        $sortTable = $split[0];
                        $keyName = $table . '.' . $split[1];
                    } else {
                        /*
                         * If you do not define which column to use as a joining column on current table, it will
                         * use a singular of a join table appended with _id
                         *
                         * ex.
                         * products -> product_id
                         */
                        $prefix = rtrim($sortTable, 's');
                        $keyName = $table . '.' . $prefix . '_id';
                    }

                    $model = $model
                        ->leftJoin($sortTable, $keyName, '=', $sortTable . '.' . $sortTableKeyName)
                        ->orderBy($sortColumn, $sortedBy)
                        ->addSelect($table . '.*');
                } else {
                    $model = $model->orderBy($orderBy, $sortedBy);
                }
            }
        }
{'fraction_non_alphanumeric': 0.12896499431315556, 'fraction_numerical': 0.0012005560470112473, 'mean_word_length': 1.200027800945232, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 81, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7245504', 'n_tokens_mistral': 3872, 'n_tokens_neox': 3648, 'n_words': 726}