Skip to content

Commit

Permalink
improved functionality for orderby using relation fields for the joins
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Blake committed Mar 28, 2018
1 parent a80f4ed commit d71b1b5
Show file tree
Hide file tree
Showing 5 changed files with 216 additions and 73 deletions.
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"description": "Search and retrieve an eloquent model entity based on complex search criteria from the model relations.",
"type": "Library",
"require": {
"laravel/framework": "5.5.*"
},
"license": "MIT",
"authors": [
Expand Down
112 changes: 112 additions & 0 deletions src/Concerns/JoinsToModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?php

namespace Assemble\EloquentSearch\Concerns;

use Closure;
use Illuminate\Database\Query\Expression;
use DB;

trait JoinsToModel
{


private function joinsToModel() {
return function($relation, $from, $dd = false) {

/**
* Wrap the attributes of the give JSON path.
*
* @param array $path
* @return array
*/
$wrapAttributes = function($path) {
$arr = array_map(function ($attribute) {
return '"'.$attribute.'"';
}, ( is_array($path) ? $path : explode('.', $path) ));
return ( is_array($path) ? $arr : implode('.', $arr) );
};

if($from != null) {
$from = (new $from)->newQuery();
} else {
$from = $this;
}
$relation = $from->getRelationWithoutConstraints($relation);


if($dd) {
// dd($this);
}

$parent = $relation->getParent();
if(property_exists($this, 'priorJoinToModelParents')) {
if(array_key_exists($parent->getTable(), $this->priorJoinToModelParents)) {
$parent->setTable($this->priorJoinToModelParents[$parent->getTable()]);
}
} else {
$this->priorJoinToModelParents = [];
}
$related = $relation->getRelated();
switch(get_class($relation)) {
case 'Illuminate\Database\Eloquent\Relations\BelongsToMany':
// For BelongsToMany
$query = $relation->getQuery()->getQuery();
$hash = $relation->getRelationCountHash();
$table = $relation->getTable();
$FK = $relation->getQualifiedForeignPivotKeyName();
$query->from($table);

// handle self relations
// if(get_class($relation->getParent()) === get_class($relation->getRelated())) {
$query->from($table.' as '.$hash);
$related->setTable($hash);
$FK = str_replace($table, $hash, $FK);
// }

break;
case 'Illuminate\Database\Eloquent\Relations\BelongsTo':
// For HasOneOrMany
$query = $relation->getQuery()->getQuery();
$hash = $relation->getRelationCountHash();
$table = $related->getTable();
$FK = $relation->getQualifiedForeignKey();

// handle self relations
// if(get_class($relation->getParent()) === get_class($relation->getRelated())) {
$query->from($table.' as '.$hash);
$related->setTable($hash);
$FK = str_replace($table, $hash, $FK);
// }

break;
default:
// For HasOneOrMany
$query = $relation->getQuery()->getQuery();
$hash = $relation->getRelationCountHash();
$table = $related->getTable();
$FK = $relation->getQualifiedForeignKeyName();

// handle self relations
// if(get_class($relation->getParent()) === get_class($relation->getRelated())) {
$query->from($table.' as '.$hash);
$related->setTable($hash);
$FK = str_replace($table, $hash, $FK);
// }
}

$this->leftJoin($query->from, $relation->getQualifiedOwnerKeyName(), '=', $FK);
$this->priorJoinToModelParents[$table] = $hash;

// $this->groupBy($relation->getQualifiedParentKeyName());

// if(empty($this->getQuery()->orders)) {
// $this->orderBy($relation->getQualifiedParentKeyName(), "asc"); // apply default order
// }

// dd($this->toSql());
return $this;
};
}


}
20 changes: 8 additions & 12 deletions src/EloquentSearchServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,28 @@
namespace Assemble\EloquentSearch;

use Illuminate\Support\ServiceProvider;
use Illuminate\Database\Eloquent\Builder;

class EloquentSearchServiceProvider extends ServiceProvider
{
use Concerns\JoinsToModel;

/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
$this->setupConfig();
}


/**
* Setup the config.
*
* @return void
*/
protected function setupConfig()
{
$source = realpath(__DIR__.'/../config/eloquent_search.php');
$source = __DIR__.'/../config/eloquent_search.php';

$this->publishes([$source => config_path('eloquent_search.php')]);

$this->mergeConfigFrom($source, 'eloquent_search');


// query helper
Builder::macro('joinsToModel', $this->joinsToModel());
}

/**
Expand Down
23 changes: 0 additions & 23 deletions src/Facades/Searcher.php

This file was deleted.

133 changes: 95 additions & 38 deletions src/Searcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Config;
use Illuminate\Support\MessageBag;
use Log;

/**
* This is the searcher class.
*
Expand Down Expand Up @@ -49,6 +50,33 @@ public function listEntities()
return array_keys($this->_ENTITIES);
}

/**
* Field / Relation Searchable On model
*
* @return \Illuminate\Http\Response
*/
public function searchableItem($model, $value)
{
if(!property_exists($model, 'searchable')) {
return false;
}
foreach($model->searchable as $key => $val) {
// simple searchable = true
if(is_string($val)) {
if($val == $value) {
return true;
}
}
// @TODO: Add callable specific to relation perhaps?
// if(is_callable($val)) {
// if($key == $value) {
// return false;
// }
// }
}
return false;
}

/**
* generate the error messages from the input
*
Expand Down Expand Up @@ -341,33 +369,63 @@ public function getSearch($search, $orderBy = null, $orderAs = null)
if(!$this->subJoined){


// if(count($order) > 0)
// {
// $last_order = null;
// foreach($order as $curOrder)
// {
// if($last_order == null){$last_order = $curOrder;}
// $ent_key = $this->getEntityClass($curOrder);

// if($ent_key == null)
// {
// return new MessageBag([
// 'messages' => [
// //@TODO: lets add more clarity here later, for now this will do.
// 'Entity does not exist: '.$curOrder
// ]
// ]);
// }
// $ent = (new $ent_key);
// $query = $query->join($ent->getTable(), $query->getModel()->getTable().'.'.$ent->getTable().'_id', '=', $ent->getTable().'.id')->orderBy($ent->getTable().'.'.$orderField, $orderDir);
// $last_order = $curOrder;
// }
// }
// elseif(isset($orderField) && isset($orderDir))
// {
// $query = $query->orderBy($orderField, $orderDir);
// }
// $this->subJoined = false;


// order by query builder
if(count($order) > 0)
{
$last_order = null;
foreach($order as $curOrder)

$ent = $this->getEntityClass($entity);
$ent = new $ent;
foreach($order as $key => $curOrder)
{
if($last_order == null){$last_order = $curOrder;}
$ent_key = $this->getEntityClass($curOrder);

if($ent_key == null)
{
if(!$this->searchableItem($ent, $curOrder)) {
return new MessageBag([
'messages' => [
//@TODO: lets add more clarity here later, for now this will do.
'Entity does not exist: '.$curOrder
]
]);
'code' => 401,
'messages' => [
//@TODO: lets add more clarity here later, for now this will do.
'You do not have permission to view this resource.'
]
]);
}
$ent = (new $ent_key);
$query = $query->join($ent->getTable(), $query->getModel()->getTable().'.'.$ent->getTable().'_id', '=', $ent->getTable().'.id')->orderBy($ent->getTable().'.'.$orderField, $orderDir);
$last_order = $curOrder;
$rel = call_user_func([$ent, $curOrder]);
$rel = get_class($rel->getRelated());
$query = $query->joinsToModel($curOrder, get_class($ent), ($key == 1));
$ent = new $rel;
}
$query = $query->orderBy($query->priorJoinToModelParents[$ent->getTable()].'.'.$orderField, $orderDir);
}
elseif(isset($orderField) && isset($orderDir))
{
$query = $query->orderBy($orderField, $orderDir);
}
$this->subJoined = false;
}

$results = $query;
Expand All @@ -390,7 +448,6 @@ public function getSearch($search, $orderBy = null, $orderAs = null)

}


/**
* SearchPattern interpreter that will search recurseively through model relations as defined.
*
Expand All @@ -408,11 +465,11 @@ private function whereHasBuilder(&$query, &$relations, &$field, &$where, &$value
//grab the relations parsed
$rel = array_shift($relations);

$curOrder = null;
if(count($order) > 0 && $rel == $order[0])
{
$curOrder = array_shift($order);
}
// $curOrder = null;
// if(count($order) > 0 && $rel == $order[0])
// {
// $curOrder = array_shift($order);
// }

$runComplex = true;
if(method_exists($rel, 'isSearchable'))
Expand Down Expand Up @@ -495,22 +552,22 @@ function ($inner) use($field, $where, $value, $rel, $relations, $last, $curOrder
* so we join here based on the standardisation assumption...
* which is needing to me migrated to configurations within models and use this as a fallback.
*/
if(!empty($curOrder)){
$ent_key = $this->getEntityClass($curOrder);

if($ent_key == null)
{
return new MessageBag([
'messages' => [
//@TODO: lets add more clarity here later, for now this will do.
'Entity does not exist: '.$curOrder
]
]);
}
$ent = (new $ent_key);
$query = $query->join($ent->getTable(), $query->getModel()->getTable().'.'.$ent->getTable().'_id', '=', $ent->getTable().'.id')->orderBy($ent->getTable().'.'.$orderField, $orderDir);
$this->subJoined = true;
}
// if(!empty($curOrder)){
// $ent_key = $this->getEntityClass($curOrder);

// if($ent_key == null)
// {
// return new MessageBag([
// 'messages' => [
// //@TODO: lets add more clarity here later, for now this will do.
// 'Entity does not exist: '.$curOrder
// ]
// ]);
// }
// $ent = (new $ent_key);
// $query = $query->join($ent->getTable(), $query->getModel()->getTable().'.'.$ent->getTable().'_id', '=', $ent->getTable().'.id')->orderBy($ent->getTable().'.'.$orderField, $orderDir);
// $this->subJoined = true;
// }
return $query;
}

Expand Down

0 comments on commit d71b1b5

Please sign in to comment.