219 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| namespace Yajra\DataTables;
 | |
| 
 | |
| use Illuminate\Database\Eloquent\Builder;
 | |
| use Illuminate\Database\Eloquent\Relations\BelongsTo;
 | |
| use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 | |
| use Illuminate\Database\Eloquent\Relations\HasOneOrMany;
 | |
| use Illuminate\Database\Eloquent\Relations\HasOneThrough;
 | |
| use Illuminate\Database\Eloquent\Relations\Relation;
 | |
| use Yajra\DataTables\Exceptions\Exception;
 | |
| 
 | |
| class EloquentDataTable extends QueryDataTable
 | |
| {
 | |
|     /**
 | |
|      * @var \Illuminate\Database\Eloquent\Builder
 | |
|      */
 | |
|     protected $query;
 | |
| 
 | |
|     /**
 | |
|      * Can the DataTable engine be created with these parameters.
 | |
|      *
 | |
|      * @param mixed $source
 | |
|      * @return bool
 | |
|      */
 | |
|     public static function canCreate($source)
 | |
|     {
 | |
|         return $source instanceof Builder || $source instanceof Relation;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * EloquentEngine constructor.
 | |
|      *
 | |
|      * @param mixed $model
 | |
|      */
 | |
|     public function __construct($model)
 | |
|     {
 | |
|         $builder = $model instanceof Builder ? $model : $model->getQuery();
 | |
|         parent::__construct($builder->getQuery());
 | |
| 
 | |
|         $this->query = $builder;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Add columns in collection.
 | |
|      *
 | |
|      * @param  array  $names
 | |
|      * @param  bool|int  $order
 | |
|      * @return $this
 | |
|      */
 | |
|     public function addColumns(array $names, $order = false)
 | |
|     {
 | |
|         foreach ($names as $name => $attribute) {
 | |
|             if (is_int($name)) {
 | |
|                 $name = $attribute;
 | |
|             }
 | |
| 
 | |
|             $this->addColumn($name, function ($model) use ($attribute) {
 | |
|                 return $model->getAttribute($attribute);
 | |
|             }, is_int($order) ? $order++ : $order);
 | |
|         }
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * If column name could not be resolved then use primary key.
 | |
|      *
 | |
|      * @return string
 | |
|      */
 | |
|     protected function getPrimaryKeyName()
 | |
|     {
 | |
|         return $this->query->getModel()->getKeyName();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Compile query builder where clause depending on configurations.
 | |
|      *
 | |
|      * @param mixed  $query
 | |
|      * @param string $columnName
 | |
|      * @param string $keyword
 | |
|      * @param string $boolean
 | |
|      */
 | |
|     protected function compileQuerySearch($query, $columnName, $keyword, $boolean = 'or')
 | |
|     {
 | |
|         $parts    = explode('.', $columnName);
 | |
|         $column   = array_pop($parts);
 | |
|         $relation = implode('.', $parts);
 | |
| 
 | |
|         if ($this->isNotEagerLoaded($relation)) {
 | |
|             return parent::compileQuerySearch($query, $columnName, $keyword, $boolean);
 | |
|         }
 | |
| 
 | |
|         $query->{$boolean . 'WhereHas'}($relation, function (Builder $query) use ($column, $keyword) {
 | |
|             parent::compileQuerySearch($query, $column, $keyword, '');
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Resolve the proper column name be used.
 | |
|      *
 | |
|      * @param string $column
 | |
|      * @return string
 | |
|      */
 | |
|     protected function resolveRelationColumn($column)
 | |
|     {
 | |
|         $parts      = explode('.', $column);
 | |
|         $columnName = array_pop($parts);
 | |
|         $relation   = implode('.', $parts);
 | |
| 
 | |
|         if ($this->isNotEagerLoaded($relation)) {
 | |
|             return $column;
 | |
|         }
 | |
| 
 | |
|         return $this->joinEagerLoadedColumn($relation, $columnName);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Check if a relation was not used on eager loading.
 | |
|      *
 | |
|      * @param  string $relation
 | |
|      * @return bool
 | |
|      */
 | |
|     protected function isNotEagerLoaded($relation)
 | |
|     {
 | |
|         return ! $relation
 | |
|             || ! array_key_exists($relation, $this->query->getEagerLoads())
 | |
|             || $relation === $this->query->getModel()->getTable();
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Join eager loaded relation and get the related column name.
 | |
|      *
 | |
|      * @param string $relation
 | |
|      * @param string $relationColumn
 | |
|      * @return string
 | |
|      * @throws \Yajra\DataTables\Exceptions\Exception
 | |
|      */
 | |
|     protected function joinEagerLoadedColumn($relation, $relationColumn)
 | |
|     {
 | |
|         $table     = '';
 | |
|         $lastQuery = $this->query;
 | |
|         foreach (explode('.', $relation) as $eachRelation) {
 | |
|             $model = $lastQuery->getRelation($eachRelation);
 | |
|             switch (true) {
 | |
|                 case $model instanceof BelongsToMany:
 | |
|                     $pivot   = $model->getTable();
 | |
|                     $pivotPK = $model->getExistenceCompareKey();
 | |
|                     $pivotFK = $model->getQualifiedParentKeyName();
 | |
|                     $this->performJoin($pivot, $pivotPK, $pivotFK);
 | |
| 
 | |
|                     $related = $model->getRelated();
 | |
|                     $table   = $related->getTable();
 | |
|                     $tablePK = $related->getForeignKey();
 | |
|                     $foreign = $pivot . '.' . $tablePK;
 | |
|                     $other   = $related->getQualifiedKeyName();
 | |
| 
 | |
|                     $lastQuery->addSelect($table . '.' . $relationColumn);
 | |
|                     $this->performJoin($table, $foreign, $other);
 | |
| 
 | |
|                     break;
 | |
| 
 | |
|                 case $model instanceof HasOneThrough:
 | |
|                     $pivot    = explode('.', $model->getQualifiedParentKeyName())[0]; // extract pivot table from key
 | |
|                     $pivotPK  = $pivot . '.' . $model->getLocalKeyName();
 | |
|                     $pivotFK  = $model->getQualifiedLocalKeyName();
 | |
|                     $this->performJoin($pivot, $pivotPK, $pivotFK);
 | |
| 
 | |
|                     $related = $model->getRelated();
 | |
|                     $table   = $related->getTable();
 | |
|                     $tablePK = $related->getForeignKey();
 | |
|                     $foreign = $pivot . '.' . $tablePK;
 | |
|                     $other   = $related->getQualifiedKeyName();
 | |
| 
 | |
|                     break;
 | |
| 
 | |
|                 case $model instanceof HasOneOrMany:
 | |
|                     $table     = $model->getRelated()->getTable();
 | |
|                     $foreign   = $model->getQualifiedForeignKeyName();
 | |
|                     $other     = $model->getQualifiedParentKeyName();
 | |
|                     break;
 | |
| 
 | |
|                 case $model instanceof BelongsTo:
 | |
|                     $table     = $model->getRelated()->getTable();
 | |
|                     $foreign   = $model->getQualifiedForeignKeyName();
 | |
|                     $other     = $model->getQualifiedOwnerKeyName();
 | |
|                     break;
 | |
| 
 | |
|                 default:
 | |
|                     throw new Exception('Relation ' . get_class($model) . ' is not yet supported.');
 | |
|             }
 | |
|             $this->performJoin($table, $foreign, $other);
 | |
|             $lastQuery = $model->getQuery();
 | |
|         }
 | |
| 
 | |
|         return $table . '.' . $relationColumn;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Perform join query.
 | |
|      *
 | |
|      * @param string $table
 | |
|      * @param string $foreign
 | |
|      * @param string $other
 | |
|      * @param string $type
 | |
|      */
 | |
|     protected function performJoin($table, $foreign, $other, $type = 'left')
 | |
|     {
 | |
|         $joins = [];
 | |
|         foreach ((array) $this->getBaseQueryBuilder()->joins as $key => $join) {
 | |
|             $joins[] = $join->table;
 | |
|         }
 | |
| 
 | |
|         if (! in_array($table, $joins)) {
 | |
|             $this->getBaseQueryBuilder()->join($table, $foreign, '=', $other, $type);
 | |
|         }
 | |
|     }
 | |
| }
 | 
