Skip to content

Instantly share code, notes, and snippets.

@RomainMazB
Created March 6, 2024 18:04
Show Gist options
  • Select an option

  • Save RomainMazB/5863bebb6f4e4d1771967f632f9b97e6 to your computer and use it in GitHub Desktop.

Select an option

Save RomainMazB/5863bebb6f4e4d1771967f632f9b97e6 to your computer and use it in GitHub Desktop.
Nova repeater with file
<?php namespace App\Nova\Fields;
use Closure;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Fields\File;
class MyFile extends File {
protected function fillAttribute(NovaRequest $request, $requestAttribute, $model, $attribute)
{
$hasExistingFile = ! is_null($this->getStoragePath());
if (is_null($file = $this->retrieveFileFromRequest($request, $requestAttribute))) {
if ($hasExistingFile) {
return $model->{$attribute} = $this->getStoragePath();
}
return;
}
$result = call_user_func(
$this->storageCallback,
$request,
$model,
$attribute,
$requestAttribute,
$this->getStorageDisk(),
$this->getStorageDir()
);
if ($result === true) {
return;
}
if ($result instanceof Closure) {
return $result;
}
if (! is_array($result)) {
return $model->{$attribute} = $result;
}
foreach ($result as $key => $value) {
$model->{$key} = $value;
}
if ($this->isPrunable() && $hasExistingFile) {
return function () use ($model, $request) {
call_user_func(
$this->deleteCallback,
$request,
$model,
$this->getStorageDisk(),
$this->getStoragePath()
);
};
}
}
}
<?php namespace App\Nova\Presets;
use Illuminate\Database\Eloquent\Model;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Fields\FieldCollection;
use Laravel\Nova\Fields\Repeater\Presets\JSON;
use Laravel\Nova\Fields\Repeater\Presets\Preset;
use Laravel\Nova\Http\Requests\NovaRequest;
use Laravel\Nova\Support\Fluent;
class MyJSONPreset implements Preset
{
/**
* Save the field value to permanent storage.
*
* @param string|null $uniqueField
* @return \Closure
*/
public function set(
NovaRequest $request,
string $requestAttribute,
Model $model,
string $attribute,
RepeatableCollection $repeatables,
$uniqueField
) {
// Clone the model to keep track of
$model->setAttribute($attribute, null);
$fieldCallbacks = collect($request->input($requestAttribute))
->map(function ($item, $blockKey) use ($request, $requestAttribute, $model, $attribute, $repeatables) {
$data = new Fluent();
$block = $repeatables->findByKey($item['type']);
$fields = FieldCollection::make($block->fields($request));
// For each field collection, return the callbacks and set the data on the model, and then return a function
// that invokes all of the callbacks;
$callbacks = $fields
->withoutUnfillable()
->withoutMissingValues()
->map(function (Field $field) use ($model, $attribute, $request, $requestAttribute, $data, $blockKey) {
$originalAttribute = $model->getOriginal($attribute);
if (!is_null($originalAttribute) && isset($originalAttribute[$blockKey])) {
$field->resolve($originalAttribute[$blockKey]['fields'], $field->attribute);
}
return $field->fillInto($request, $data, $field->attribute, "{$requestAttribute}.{$blockKey}.fields.{$field->attribute}");
})
->filter(function ($callback) {
return is_callable($callback);
});
// Set the block type on the data object
$model->setAttribute("{$attribute}->{$blockKey}->type", $block->key());
// Set the data on the model
foreach ($data->getAttributes() as $k => $v) {
$model->setAttribute("{$attribute}->{$blockKey}->fields->{$k}", $v);
}
// Return a function that calls the callbacks from the fields
return function () use ($callbacks) {
return $callbacks->each->__invoke();
};
});
return function () use ($fieldCallbacks) {
return collect($fieldCallbacks)->each->__invoke();
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment