Cannot use translatable file
Hi,
I'm trying to use your amazing package with https://github.com/outl1ne/nova-translatable (mostly because language selector in nova is more user friendly) on Nova v4.
I've seen that you already adressed something similar here : https://github.com/oneduo/nova-file-manager/issues/168 and in docs (Third party part).
However I've came through an error (see below).
I've seen that there is a "storageCallback" property in vendor/oneduo/nova-file-manager/src/FileManager.php, but as far as I'm concerned I'm not able to use it.
I tried to use this callback to solve the problem this way without success :
FileManager::make(__('Video'), 'video', function(...) { // callback })
and FileManager::make(__('Video'), 'video')->storageCallback()
Do you have any idea how to solve the problem ?
Please find the error shown below when clicking on "Save" on the ressource.
Error
{ "message": "json_decode(): Argument #1 ($json) must be of type string, array given", "exception": "TypeError", "file": "/var/www/html/vendor/oneduo/nova-file-manager/src/FileManager.php", "line": 138, "trace": [ { "file": "/var/www/html/vendor/oneduo/nova-file-manager/src/FileManager.php", "line": 138, "function": "json_decode" }, { "function": "Oneduo\NovaFileManager\{closure}", "class": "Oneduo\NovaFileManager\FileManager", "type": "->" }, { "file": "/var/www/html/vendor/oneduo/nova-file-manager/src/FileManager.php", "line": 102, "function": "call_user_func" }, { "file": "/var/www/html/vendor/laravel/nova/src/Fields/Field.php", "line": 436, "function": "fillAttribute", "class": "Oneduo\NovaFileManager\FileManager", "type": "->" }, { "file": "/var/www/html/vendor/laravel/nova/src/Fields/Field.php", "line": 412, "function": "fillInto", "class": "Laravel\Nova\Fields\Field", "type": "->" }, { "file": "/var/www/html/vendor/laravel/framework/src/Illuminate/Collections/HigherOrderCollectionProxy.php", "line": 65, "function": "fill", "class": "Laravel\Nova\Fields\Field", "type": "->" }, { "function": "Illuminate\Support\{closure}", "class": "Illuminate\Support\HigherOrderCollectionProxy", "type": "->" }, { "file": "/var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Arr.php", "line": 609, "function": "array_map" }, { "file": "/var/www/html/vendor/laravel/framework/src/Illuminate/Collections/Collection.php", "line": 795, "function": "map", "class": "Illuminate\Support\Arr", "type": "::" }, { "file": "/var/www/html/vendor/laravel/framework/src/Illuminate/Collections/HigherOrderCollectionProxy.php", "line": 64, "function": "map", "class": "Illuminate\Support\Collection", "type": "->" }, { "file": "/var/www/html/vendor/laravel/nova/src/FillsFields.php", "line": 100, "function": "__call", "class": "Illuminate\Support\HigherOrderCollectionProxy", "type": "->" }, { "file": "/var/www/html/vendor/laravel/nova/src/FillsFields.php", "line": 37, "function": "fillFields", "class": "Laravel\Nova\Resource", "type": "::" }, ... }
Bumping on this, please don't close the subject yet 🥇
I was able to use the callback but still encountering save errors, using wrapper function :
FileManager::registerWrapper('videos', function (FileManager $field) {
$field->storageCallback = function (NovaRequest $request, $model, string $attribute, string $requestAttribute) {
$value = $request->input($requestAttribute);
// Do things
return [$attribute => $value];
};
// configure the field as you used to
return $field;
});
Well I guess that's impossible to achieve right now. Best thing achievable was to store the json with the right format in DB but after that https://github.com/outl1ne/nova-translatable does not provide any mean to cast on their meta, which they use to populate the db.
"nova-translatable" populates "translated" meta with basic json instead of (new Asset(...$value))->toArray() and I found no way to fix this this sadly, even with resolveUsing() and displayUsing().
Maybe @Tarpsvo or someone at outl1ne could get a look ?
Final code for reference, for anyone interested, create a wrapper in NovaServiceProvider in register() method :
FileManager::registerWrapper('translatable-file', function (FileManager $field) {
$field->storageCallback = function (NovaRequest $request, $model, string $attribute, string $requestAttribute) {
$value = $request->input($attribute);
$formattedAttribute = explode('.*', $attribute)[0];
// Only way I found to get all languages sent with the request :'(
$translatedFiles = $request->all()[$formattedAttribute] ?? [];
$result = [];
foreach ($translatedFiles as $locale => $value) {
try {
$payload = json_decode($value ?? '', true, 512, JSON_THROW_ON_ERROR);
} catch (\JsonException) {
$payload = [];
}
// Sometimes its wrapped in a sub 0 index
$result[$locale] = (new Asset(...($payload[0] ?? $payload)))->toArray();
}
return [
$formattedAttribute => $result
];
};
return $field
->resolveUrlUsing(function (NovaRequest $request, string $path, string $disk, LocalFilesystemAdapter|Filesystem $filesystem) {
if (config('filesystems.disks.'.$disk.'.disk') !== "public") {
return $filesystem->temporaryUrl($path, now()->addMinutes(5));
}
$url = $filesystem->url($path);
return $url;
})
->filesystem(fn() => 'files')
;
});`
Hey @MattLoyeD
Could you please provide a minimal reproduction setup/repo please?
I will take a look then
Cheers
Hi @Rezrazi :)
Sure here it is :
1 - Install https://github.com/outl1ne/nova-translatable on a Nova 4/Laravel 11 install.
2 - Create a nova resource for a model with json column (let's name it file). Please note that this column is casted via Asset class.
3 - Add a field for the file column like the following :
FileManager::make('File', 'file')->wrapper('translatable-file')->translatable(),
Here datas cannot be saved, however I was able to do it via storageCallback in the wrapper function.
4 - Register wrapper in NovaServiceProvider (see wrapper code in my previous comment).
5 - Datas are now stored as they should in DB, for example :
{ en: { path: 'f1.mp4', disk: 'public' }, fr: { path: 'f2.mp4', disk: 'public' } }
However I was never able to display each file correctly in frontend in Nova afterwards, seems like FileManager field is always considered as empty even if Nova API response clearly indicates what's inside the DB and therefore should work.
Something strange is that values where not casted in the response, making me think nova-translatable bypasses this part and then make nova-file-manager inoperant.
Hope this fits what you were asking !
Sorry if I have to insist @MattLoyeD but could you make into a public repository and share the link.
As schedules are really tight with day-job responsibilities, it will be really helpful to have a ready to use reproduction.
Sqlite could be used too
Thanks again, will take a look once a repo is made available
@Rezrazi I'll try to find some time next week.