Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

L11 Compatability #10

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Dusk Test Repo: https://github.com/Formfeed-UK/nova-dependable-panel-tests

## Requirements

- `php: ^7.3|^8.0`
- `php: >=8.2`
- `laravel/nova: ^4.0`

## Features
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
],
"license": "MIT",
"require": {
"php": "^7.3|^8.0",
"php": ">=8.2",
"laravel/nova": "^4.0",
"nova-kit/nova-packages-tool":"^1.0",
"formfeed-uk/nova-subfield-dependson": "^2.0.0"
"laravel/framework": "^8.0|^9.0|^10.0|^11.0"
},
"autoload": {
"psr-4": {
Expand Down
6 changes: 4 additions & 2 deletions src/FieldServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
use Laravel\Nova\Events\ServingNova;
use Laravel\Nova\Nova;

use Formfeed\DependablePanel\Http\Middleware\InterceptDependentFields;
use Formfeed\DependablePanel\Http\Middleware\InterceptSubfieldDependsOn;
use Formfeed\DependablePanel\Http\Middleware\InterceptDisplayFields;
use Formfeed\DependablePanel\Http\Middleware\InterceptValidationFailure;

Expand Down Expand Up @@ -43,6 +43,7 @@ public function addMiddleware()
$router = $this->app['router'];

if ($router->hasMiddlewareGroup('nova')) {
$router->pushMiddlewareToGroup('nova', InterceptSubfieldDependsOn::class);
$router->pushMiddlewareToGroup('nova', InterceptValidationFailure::class);
$router->pushMiddlewareToGroup('nova', InterceptDisplayFields::class);
return;
Expand All @@ -51,7 +52,8 @@ public function addMiddleware()
if (! $this->app->configurationIsCached()) {
config()->set('nova.middleware', array_merge(
config('nova.middleware', []),
[InterceptValidationFailure::class,
[InterceptSubfieldDependsOn::class,
InterceptValidationFailure::class,
InterceptDisplayFields::class]
));
}
Expand Down
167 changes: 167 additions & 0 deletions src/Http/Middleware/InterceptSubfieldDependsOn.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
<?php

namespace Formfeed\DependablePanel\Http\Middleware;

use ArrayObject;
use Closure;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

use Laravel\Nova\Fields\FieldCollection;
use Laravel\Nova\Http\Controllers\UpdateFieldController;
use Laravel\Nova\Http\Controllers\CreationFieldController;
use Laravel\Nova\Http\Controllers\CreationFieldSyncController;
use Laravel\Nova\Http\Controllers\UpdatePivotFieldController;
use Laravel\Nova\Http\Controllers\CreationPivotFieldController;
use Laravel\Nova\Http\Requests\NovaRequest;

use Laravel\Nova\Http\Resources\UpdateViewResource;
use Laravel\Nova\Http\Resources\UpdatePivotFieldResource;
use Laravel\Nova\Http\Resources\CreateViewResource;
use Laravel\Nova\Http\Resources\CreationPivotFieldResource;
use Laravel\Nova\Http\Resources\ReplicateViewResource;

use Laravel\Nova\Fields\Field;
use Laravel\Nova\Http\Requests\ResourceCreateOrAttachRequest;
use Laravel\Nova\Http\Requests\ResourceUpdateOrUpdateAttachedRequest;

class InterceptSubfieldDependsOn
{
/**
* Handle the given request and get the response.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handle(Request $request, Closure $next): Response {

// Pass through if closure, getController is unsafe to use with closures, if its a closure it's not a Nova DependsOn request
if (array_key_exists("uses", $request->route()->action) && $request->route()->action['uses'] instanceof Closure) {
return $next($request);
}

$novaRequest = NovaRequest::createFrom($request);

if (!$this->isDependentFieldRequest($request)) {
return $next($request);
}

if (!$this->resourceHasSubfields($novaRequest)) {
return $next($request);
}

$response = $next($request);

if ($response instanceof JsonResponse) {
$content = $response->getOriginalContent();

$field = [];

// If the Field is successfully resolved via another middleware or resource method, just use that
if ($content instanceof Field) {
$field = $content;
}

// If the Field is not resolved, try to find it and sync depends on
if ($content instanceof ArrayObject && $content->count() === 0) {
$field = $this->findField($novaRequest, $request->input("component"));
if ($field instanceof Field) {
$field->syncDependsOn($novaRequest);
}
}

// If there are additional actions needed after dependsOn sync, run them
if (method_exists($field, "afterDependsOnSync")) {
$field = $field->afterDependsOnSync($novaRequest) ?? $field;
}

$response = response()->json($field);
}

return $response;
}

protected function isDependentFieldRequest(Request $request) {
return ($request->isMethod("PATCH") && $this->isNovaFieldController($request));
}

protected function findField(NovaRequest $request, string $componentKey) {
$fields = $this->getResourceFields($request);
return $this->findNestedField($request, $fields, $componentKey);
}

protected function findNestedField(NovaRequest $request, FieldCollection $fields, string $componentKey) {

if ($fields->count() === 0) {
return [];
}

return $fields->first(fn ($field) => ($field->dependentComponentKey() === $componentKey)) ?? $this->findNestedField($request, $this->getSubfields($request, $fields), $componentKey);
}

protected function getSubfields(NovaRequest $request, FieldCollection $fields) {
return rescue(function () use ($fields, $request) {
return $fields->filter(function ($field) use ($request) {
return $this->fieldHasSubfields($request, $field);
})->map(function ($field) use ($request) {
return $field->getSubfields($request);
})->flatten();
}, FieldCollection::make([]), false);
}

protected function fieldHasSubfields(NovaRequest $request, Field $field): bool {
return method_exists($field, "getSubfields") && method_exists($field, "hasSubfields") && $field->hasSubfields($request);
}

protected function getResourceFields(NovaRequest $request): FieldCollection {
return $this->getFieldsForRequest($request);
}

protected function resourceHasSubfields(NovaRequest $request): bool {
return $request->newResource()->availableFields($request)->contains(function ($field) {
return method_exists($field, "getSubfields") && method_exists($field, "hasSubfields");
});
}

protected function isNovaFieldController(Request $request) {
$routeController = $request->route()->getController();
return in_array(get_class($routeController), [
UpdateFieldController::class,
UpdatePivotFieldController::class,
CreationFieldController::class,
CreationFieldSyncController::class,
CreationPivotFieldController::class,
]);
}

protected function getFieldsForRequest(NovaRequest $request) {
$routeController = $request->route()->getController();
switch (get_class($routeController)) {
case UpdateFieldController::class: {
$resource = UpdateViewResource::make()->newResourceWith(ResourceUpdateOrUpdateAttachedRequest::createFrom($request));
return $resource->creationFieldsWithinPanels($request);
}
case UpdatePivotFieldController::class: {
$resource = UpdatePivotFieldResource::make()->newResourceWith(ResourceUpdateOrUpdateAttachedRequest::createFrom($request));
return $resource->updatePivotFields($request, $request->relatedResource);
}
case CreationFieldController::class:
case CreationFieldSyncController::class: {
$resource = $request->has('fromResourceId')
? ReplicateViewResource::make($request->fromResourceId)->newResourceWith(ResourceCreateOrAttachRequest::createFrom($request))
: CreateViewResource::make()->newResourceWith(ResourceCreateOrAttachRequest::createFrom($request));
return $resource->updateFieldsWithinPanels($request);
}
case CreationPivotFieldController::class: {
$resource = CreationPivotFieldResource::make()->newResourceWith(ResourceCreateOrAttachRequest::createFrom($request));
return $resource->creationPivotFields($request, $request->relatedResource);
}
default: {
return FieldCollection::make([]);
}
}
}
}
16 changes: 16 additions & 0 deletions src/Subfields/Subfield.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Formfeed\DependablePanel\Subfields;

use Laravel\Nova\Fields\FieldCollection;

interface Subfield
{

public function hasSubfields(): bool;

public function getSubfields(): FieldCollection;

public function afterDependsOnSync() : self;

}