D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
home
/
tattooscyy
/
test
/
vendor
/
yajra
/
laravel-datatables-oracle
/
src
/
Engines
/
Filename :
BaseEngine.php
back
Copy
<?php namespace Yajra\Datatables\Engines; use Illuminate\Http\JsonResponse; use Illuminate\Support\Facades\Config; use Illuminate\Support\Str; use League\Fractal\Resource\Collection; use Yajra\Datatables\Contracts\DataTableEngineContract; use Yajra\Datatables\Helper; use Yajra\Datatables\Processors\DataProcessor; /** * Class BaseEngine. * * @package Yajra\Datatables\Engines * @author Arjay Angeles <aqangeles@gmail.com> */ abstract class BaseEngine implements DataTableEngineContract { /** * Datatables Request object. * * @var \Yajra\Datatables\Request */ public $request; /** * Database connection used. * * @var \Illuminate\Database\Connection */ protected $connection; /** * Builder object. * * @var \Illuminate\Database\Query\Builder|\Illuminate\Database\Eloquent\Builder */ protected $query; /** * Query builder object. * * @var \Illuminate\Database\Query\Builder */ protected $builder; /** * Array of result columns/fields. * * @var array */ protected $columns = []; /** * DT columns definitions container (add/edit/remove/filter/order/escape). * * @var array */ protected $columnDef = [ 'index' => false, 'append' => [], 'edit' => [], 'excess' => ['rn', 'row_num'], 'filter' => [], 'order' => [], 'escape' => [], 'blacklist' => ['password', 'remember_token'], 'whitelist' => '*', ]; /** * Query type. * * @var string */ protected $query_type; /** * Extra/Added columns. * * @var array */ protected $extraColumns = []; /** * Total records. * * @var int */ protected $totalRecords = 0; /** * Total filtered records. * * @var int */ protected $filteredRecords = 0; /** * Auto-filter flag. * * @var bool */ protected $autoFilter = true; /** * Callback to override global search. * * @var callable */ protected $filterCallback; /** * Parameters to passed on filterCallback. * * @var mixed */ protected $filterCallbackParameters; /** * DT row templates container. * * @var array */ protected $templates = [ 'DT_RowId' => '', 'DT_RowClass' => '', 'DT_RowData' => [], 'DT_RowAttr' => [], ]; /** * Output transformer. * * @var \League\Fractal\TransformerAbstract */ protected $transformer = null; /** * Database prefix * * @var string */ protected $prefix; /** * Database driver used. * * @var string */ protected $database; /** * [internal] Track if any filter was applied for at least one column * * @var boolean */ protected $isFilterApplied = false; /** * Fractal serializer class. * * @var string|null */ protected $serializer = null; /** * Custom ordering callback. * * @var callable */ protected $orderCallback; /** * Skip paginate as needed. * * @var bool */ protected $skipPaging = false; /** * Array of data to append on json response. * * @var array */ private $appends = []; /** * Setup search keyword. * * @param string $value * @return string */ public function setupKeyword($value) { if ($this->isSmartSearch()) { $keyword = '%' . $value . '%'; if ($this->isWildcard()) { $keyword = $this->wildcardLikeString($value); } // remove escaping slash added on js script request $keyword = str_replace('\\', '%', $keyword); return $keyword; } return $value; } /** * Check if DataTables uses smart search. * * @return bool */ protected function isSmartSearch() { return Config::get('datatables.search.smart', true); } /** * Get config use wild card status. * * @return bool */ public function isWildcard() { return Config::get('datatables.search.use_wildcards', false); } /** * Adds % wildcards to the given string. * * @param string $str * @param bool $lowercase * @return string */ public function wildcardLikeString($str, $lowercase = true) { $wild = '%'; $chars = preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY); if (count($chars) > 0) { foreach ($chars as $char) { $wild .= $char . '%'; } } if ($lowercase) { $wild = Str::lower($wild); } return $wild; } /** * Will prefix column if needed. * * @param string $column * @return string */ public function prefixColumn($column) { $table_names = $this->tableNames(); if (count( array_filter($table_names, function ($value) use (&$column) { return strpos($column, $value . '.') === 0; }) )) { // the column starts with one of the table names $column = $this->prefix . $column; } return $column; } /** * Will look through the query and all it's joins to determine the table names. * * @return array */ public function tableNames() { $names = []; $query = $this->getQueryBuilder(); $names[] = $query->from; $joins = $query->joins ?: []; $databasePrefix = $this->prefix; foreach ($joins as $join) { $table = preg_split('/ as /i', $join->table); $names[] = $table[0]; if (isset($table[1]) && ! empty($databasePrefix) && strpos($table[1], $databasePrefix) == 0) { $names[] = preg_replace('/^' . $databasePrefix . '/', '', $table[1]); } } return $names; } /** * Get Query Builder object. * * @param mixed $instance * @return mixed */ public function getQueryBuilder($instance = null) { if (! $instance) { $instance = $this->query; } if ($this->isQueryBuilder()) { return $instance; } return $instance->getQuery(); } /** * Check query type is a builder. * * @return bool */ public function isQueryBuilder() { return $this->query_type == 'builder'; } /** * Add column in collection. * * @param string $name * @param string|callable $content * @param bool|int $order * @return $this */ public function addColumn($name, $content, $order = false) { $this->extraColumns[] = $name; $this->columnDef['append'][] = ['name' => $name, 'content' => $content, 'order' => $order]; return $this; } /** * Add DT row index column on response. * * @return $this */ public function addIndexColumn() { $this->columnDef['index'] = true; return $this; } /** * Edit column's content. * * @param string $name * @param string|callable $content * @return $this */ public function editColumn($name, $content) { $this->columnDef['edit'][] = ['name' => $name, 'content' => $content]; return $this; } /** * Remove column from collection. * * @return $this */ public function removeColumn() { $names = func_get_args(); $this->columnDef['excess'] = array_merge($this->columnDef['excess'], $names); return $this; } /** * Declare columns to escape values. * * @param string|array $columns * @return $this */ public function escapeColumns($columns = '*') { $this->columnDef['escape'] = $columns; return $this; } /** * Allows previous API calls where the methods were snake_case. * Will convert a camelCase API call to a snake_case call. * Allow query builder method to be used by the engine. * * @param string $name * @param array $arguments * @return mixed */ public function __call($name, $arguments) { $name = Str::camel(Str::lower($name)); if (method_exists($this, $name)) { return call_user_func_array([$this, $name], $arguments); } elseif (method_exists($this->getQueryBuilder(), $name)) { call_user_func_array([$this->getQueryBuilder(), $name], $arguments); } else { trigger_error('Call to undefined method ' . __CLASS__ . '::' . $name . '()', E_USER_ERROR); } return $this; } /** * Sets DT_RowClass template. * result: <tr class="output_from_your_template">. * * @param string|callable $content * @return $this */ public function setRowClass($content) { $this->templates['DT_RowClass'] = $content; return $this; } /** * Sets DT_RowId template. * result: <tr id="output_from_your_template">. * * @param string|callable $content * @return $this */ public function setRowId($content) { $this->templates['DT_RowId'] = $content; return $this; } /** * Set DT_RowData templates. * * @param array $data * @return $this */ public function setRowData(array $data) { $this->templates['DT_RowData'] = $data; return $this; } /** * Add DT_RowData template. * * @param string $key * @param string|callable $value * @return $this */ public function addRowData($key, $value) { $this->templates['DT_RowData'][$key] = $value; return $this; } /** * Set DT_RowAttr templates. * result: <tr attr1="attr1" attr2="attr2">. * * @param array $data * @return $this */ public function setRowAttr(array $data) { $this->templates['DT_RowAttr'] = $data; return $this; } /** * Add DT_RowAttr template. * * @param string $key * @param string|callable $value * @return $this */ public function addRowAttr($key, $value) { $this->templates['DT_RowAttr'][$key] = $value; return $this; } /** * Override default column filter search. * * @param string $column * @param string|callable $method * @return $this * @internal param $mixed ...,... All the individual parameters required for specified $method * @internal string $1 Special variable that returns the requested search keyword. */ public function filterColumn($column, $method) { $params = func_get_args(); $this->columnDef['filter'][$column] = ['method' => $method, 'parameters' => array_splice($params, 2)]; return $this; } /** * Order each given columns versus the given custom sql. * * @param array $columns * @param string $sql * @param array $bindings * @return $this */ public function orderColumns(array $columns, $sql, $bindings = []) { foreach ($columns as $column) { $this->orderColumn($column, str_replace(':column', $column, $sql), $bindings); } return $this; } /** * Override default column ordering. * * @param string $column * @param string $sql * @param array $bindings * @return $this * @internal string $1 Special variable that returns the requested order direction of the column. */ public function orderColumn($column, $sql, $bindings = []) { $this->columnDef['order'][$column] = ['method' => 'orderByRaw', 'parameters' => [$sql, $bindings]]; return $this; } /** * Set data output transformer. * * @param \League\Fractal\TransformerAbstract $transformer * @return $this */ public function setTransformer($transformer) { $this->transformer = $transformer; return $this; } /** * Set fractal serializer class. * * @param string $serializer * @return $this */ public function setSerializer($serializer) { $this->serializer = $serializer; return $this; } /** * Organizes works. * * @param bool $mDataSupport * @param bool $orderFirst * @return \Illuminate\Http\JsonResponse */ public function make($mDataSupport = false, $orderFirst = false) { $this->totalRecords = $this->totalCount(); if ($this->totalRecords) { $this->orderRecords(! $orderFirst); $this->filterRecords(); $this->orderRecords($orderFirst); $this->paginate(); } return $this->render($mDataSupport); } /** * Sort records. * * @param boolean $skip * @return void */ public function orderRecords($skip) { if (! $skip) { $this->ordering(); } } /** * Perform necessary filters. * * @return void */ public function filterRecords() { if ($this->autoFilter && $this->request->isSearchable()) { $this->filtering(); } if (is_callable($this->filterCallback)) { call_user_func($this->filterCallback, $this->filterCallbackParameters); } $this->columnSearch(); $this->filteredRecords = $this->isFilterApplied ? $this->count() : $this->totalRecords; } /** * Apply pagination. * * @return void */ public function paginate() { if ($this->request->isPaginationable() && ! $this->skipPaging) { $this->paging(); } } /** * Render json response. * * @param bool $object * @return \Illuminate\Http\JsonResponse */ public function render($object = false) { $output = array_merge([ 'draw' => (int) $this->request['draw'], 'recordsTotal' => $this->totalRecords, 'recordsFiltered' => $this->filteredRecords, ], $this->appends); if (isset($this->transformer)) { $fractal = app('datatables.fractal'); if ($this->serializer) { $fractal->setSerializer($this->createSerializer()); } //Get transformer reflection //Firs method parameter should be data/object to transform $reflection = new \ReflectionMethod($this->transformer, 'transform'); $parameter = $reflection->getParameters()[0]; //If parameter is class assuming it requires object //Else just pass array by default if ($parameter->getClass()) { $resource = new Collection($this->results(), $this->createTransformer()); } else { $resource = new Collection( $this->getProcessedData($object), $this->createTransformer() ); } $collection = $fractal->createData($resource)->toArray(); $output['data'] = $collection['data']; } else { $output['data'] = Helper::transform($this->getProcessedData($object)); } if ($this->isDebugging()) { $output = $this->showDebugger($output); } return new JsonResponse($output); } /** * Get or create transformer serializer instance. * * @return \League\Fractal\Serializer\SerializerAbstract */ protected function createSerializer() { if ($this->serializer instanceof \League\Fractal\Serializer\SerializerAbstract) { return $this->serializer; } return new $this->serializer(); } /** * Get or create transformer instance. * * @return \League\Fractal\TransformerAbstract */ protected function createTransformer() { if ($this->transformer instanceof \League\Fractal\TransformerAbstract) { return $this->transformer; } return new $this->transformer(); } /** * Get processed data * * @param bool|false $object * @return array */ private function getProcessedData($object = false) { $processor = new DataProcessor( $this->results(), $this->columnDef, $this->templates, $this->request['start'] ); return $processor->process($object); } /** * Check if app is in debug mode. * * @return bool */ public function isDebugging() { return Config::get('app.debug', false); } /** * Append debug parameters on output. * * @param array $output * @return array */ public function showDebugger(array $output) { $output['queries'] = $this->connection->getQueryLog(); $output['input'] = $this->request->all(); return $output; } /** * Update flags to disable global search * * @param callable $callback * @param mixed $parameters * @param bool $autoFilter */ public function overrideGlobalSearch(callable $callback, $parameters, $autoFilter = false) { $this->autoFilter = $autoFilter; $this->isFilterApplied = true; $this->filterCallback = $callback; $this->filterCallbackParameters = $parameters; } /** * Get config is case insensitive status. * * @return bool */ public function isCaseInsensitive() { return Config::get('datatables.search.case_insensitive', false); } /** * Append data on json response. * * @param mixed $key * @param mixed $value * @return $this */ public function with($key, $value = '') { if (is_array($key)) { $this->appends = $key; } elseif (is_callable($value)) { $this->appends[$key] = value($value); } else { $this->appends[$key] = value($value); } return $this; } /** * Override default ordering method with a closure callback. * * @param callable $closure * @return $this */ public function order(callable $closure) { $this->orderCallback = $closure; return $this; } /** * Update list of columns that is not allowed for search/sort. * * @param array $blacklist * @return $this */ public function blacklist(array $blacklist) { $this->columnDef['blacklist'] = $blacklist; return $this; } /** * Update list of columns that is not allowed for search/sort. * * @param string|array $whitelist * @return $this */ public function whitelist($whitelist = '*') { $this->columnDef['whitelist'] = $whitelist; return $this; } /** * Set smart search config at runtime. * * @param bool $bool * @return $this */ public function smart($bool = true) { Config::set('datatables.search.smart', $bool); return $this; } /** * Set total records manually. * * @param int $total * @return $this */ public function setTotalRecords($total) { $this->totalRecords = $total; return $this; } /** * Skip pagination as needed. */ public function skipPaging() { $this->skipPaging = true; return $this; } /** * Check if column is blacklisted. * * @param string $column * @return bool */ protected function isBlacklisted($column) { if (in_array($column, $this->columnDef['blacklist'])) { return true; } if ($this->columnDef['whitelist'] === '*' || in_array($column, $this->columnDef['whitelist'])) { return false; } return true; } /** * Get column name to be use for filtering and sorting. * * @param integer $index * @param bool $wantsAlias * @return string */ protected function getColumnName($index, $wantsAlias = false) { $column = $this->request->columnName($index); // DataTables is using make(false) if (is_numeric($column)) { $column = $this->getColumnNameByIndex($index); } if (Str::contains(Str::upper($column), ' AS ')) { $column = $this->extractColumnName($column, $wantsAlias); } return $column; } /** * Get column name by order column index. * * @param int $index * @return mixed */ protected function getColumnNameByIndex($index) { $name = isset($this->columns[$index]) && $this->columns[$index] <> '*' ? $this->columns[$index] : $this->getPrimaryKeyName(); return in_array($name, $this->extraColumns, true) ? $this->getPrimaryKeyName() : $name; } /** * If column name could not be resolved then use primary key. * * @return string */ protected function getPrimaryKeyName() { if ($this->isEloquent()) { return $this->query->getModel()->getKeyName(); } return 'id'; } /** * Check if the engine used was eloquent. * * @return bool */ protected function isEloquent() { return $this->query_type === 'eloquent'; } /** * Get column name from string. * * @param string $str * @param bool $wantsAlias * @return string */ protected function extractColumnName($str, $wantsAlias) { $matches = explode(' as ', Str::lower($str)); if (! empty($matches)) { if ($wantsAlias) { return array_pop($matches); } else { return array_shift($matches); } } elseif (strpos($str, '.')) { $array = explode('.', $str); return array_pop($array); } return $str; } /** * Check if the current sql language is based on oracle syntax. * * @return bool */ protected function isOracleSql() { return in_array($this->database, ['oracle', 'oci8']); } }