Last active
January 2, 2020 05:01
-
-
Save lesstif/1ec531c38137744a1d2c7931729f0ca4 to your computer and use it in GitHub Desktop.
laravel nova 의 attachable 이 relation 때문에 느릴때 사용하는 AttachableController 컨트롤러.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Laravel\Nova\Http\Controllers; | |
use Laravel\Scout\Searchable; | |
use Laravel\Nova\Fields\Field; | |
use Laravel\Nova\TrashedStatus; | |
use Illuminate\Routing\Controller; | |
use Laravel\Nova\Fields\MorphToMany; | |
use Laravel\Nova\Fields\BelongsToMany; | |
use Laravel\Nova\Http\Requests\NovaRequest; | |
/** | |
* 과다한 relation 으로 attach 쿼리가 느려서 검색엔진 사용하도록 수정한 컨트롤러 | |
* | |
* Class AttachableController | |
* @package Laravel\Nova\Http\Controllers | |
* | |
* cp laravel-nova-AttachableController.php vendor/laravel/nova/src/Http/Controllers/AttachableController.php | |
*/ | |
class AttachableController extends Controller | |
{ | |
public function index(NovaRequest $request) | |
{ | |
return $this->indexNew($request); | |
} | |
/** | |
* List the available related resources for a given resource. | |
* | |
* @param \Laravel\Nova\Http\Requests\NovaRequest $request | |
* @return \Illuminate\Http\Response | |
*/ | |
public function indexNew(NovaRequest $request) | |
{ | |
$field = $request->newResource() | |
->availableFields($request) | |
->filter(function ($field) { | |
return $field instanceof BelongsToMany || $field instanceof MorphToMany; | |
}) | |
->firstWhere('resourceName', $request->field); | |
$withTrashed = $this->shouldIncludeTrashed( | |
$request, | |
$associatedResource = $field->resourceClass | |
); | |
// get ids that is already attached | |
$keys = $this->getAttachedKeys($request, $field); | |
// get model class name | |
$model = $field->resourceClass::${'model'}; | |
if ($this->isClassSearchable($model)) { | |
$class = new $model(); | |
// TODO withTrashed 옵션 추가(->whereNotNull('deleted_at')) | |
$records = $class->search($request->search)->paginate(500); | |
$resources = $records->map(function ($item, $key) use ($keys) { | |
$title = $item->title ?? null; | |
if ($title === null) { | |
$title = $item->name ?? null; | |
} | |
return [ | |
'display' => $key . 'th (' . $item->id . ' => ' . $title . ')', | |
'value' => $item->id, | |
]; | |
})->reject(function ($item) use($keys){ | |
// 이미 추가된 element 제외 | |
if (in_array($item['value'], $keys)) { | |
return true; | |
} | |
return false; | |
})->sortBy('value'); | |
$softDeletes = null; | |
} else { | |
$parentResource = $request->findResourceOrFail(); | |
$resources = $field->buildAttachableQuery($request, $withTrashed)->get() | |
->mapInto($field->resourceClass) | |
->filter(function ($resource) use ($request, $parentResource) { | |
return $parentResource->authorizedToAttach($request, $resource->resource); | |
}) | |
->map(function ($resource) use ($request, $field) { | |
return $field->formatAttachableResource($request, $resource); | |
}) | |
->reject(function ($resource) use ($keys) { | |
return in_array($resource['value'], $keys); | |
})->sortBy('display', SORT_NATURAL | SORT_FLAG_CASE)->values(); | |
$softDeletes = $associatedResource::softDeletes(); | |
} | |
return compact(['resources', 'withTrashed', 'softDeletes']); | |
} | |
/** | |
* List the available related resources for a given resource. | |
* | |
* @param \Laravel\Nova\Http\Requests\NovaRequest $request | |
* @return \Illuminate\Http\Response | |
*/ | |
public function indexOrg(NovaRequest $request) | |
{ | |
$field = $request->newResource() | |
->availableFields($request) | |
->filter(function ($field) { | |
return $field instanceof BelongsToMany || $field instanceof MorphToMany; | |
}) | |
->firstWhere('resourceName', $request->field); | |
$withTrashed = $this->shouldIncludeTrashed( | |
$request, | |
$associatedResource = $field->resourceClass | |
); | |
$parentResource = $request->findResourceOrFail(); | |
$ret = [ | |
'resources' => $field->buildAttachableQuery($request, $withTrashed)->get() | |
->mapInto($field->resourceClass) | |
->filter(function ($resource) use ($request, $parentResource) { | |
return $parentResource->authorizedToAttach($request, $resource->resource); | |
}) | |
->map(function ($resource) use ($request, $field) { | |
return $field->formatAttachableResource($request, $resource); | |
})->sortBy('display', SORT_NATURAL | SORT_FLAG_CASE)->values(), | |
'withTrashed' => $withTrashed, | |
'softDeletes' => $associatedResource::softDeletes(), | |
]; | |
return $ret; | |
} | |
/** | |
* Determine if the query should include trashed models. | |
* | |
* @param \Laravel\Nova\Http\Requests\NovaRequest $request | |
* @param string $associatedResource | |
* @return bool | |
*/ | |
protected function shouldIncludeTrashed(NovaRequest $request, $associatedResource) | |
{ | |
if ($request->withTrashed === 'true') { | |
return true; | |
} | |
$associatedModel = $associatedResource::newModel(); | |
if ($request->current && $associatedResource::softDeletes()) { | |
$associatedModel = $associatedModel->newQueryWithoutScopes()->find($request->current); | |
return $associatedModel ? $associatedModel->trashed() : false; | |
} | |
return false; | |
} | |
protected function isClassSearchable($fqn) | |
{ | |
if (!in_array(Searchable::class, class_uses_recursive($fqn), true)) { | |
return false; | |
} | |
return true; | |
} | |
/** | |
* MorphTo relation 시 이미 추가된 model id 가져오기 | |
* | |
* @param NovaRequest $request | |
* @param Field $field | |
* @return mixed | |
*/ | |
protected function getAttachedKeys(NovaRequest $request, Field $field) | |
{ | |
$model = $request->findModelOrFail(); | |
$key = $field->resourceClass::newModel()->getQualifiedKeyName(); | |
return $model->{$field->attribute}()->select($key)->pluck($key)->toArray(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment