feature: Required import mapping for new records only

This commit is contained in:
Dan Harrin
2024-08-12 17:20:09 +01:00
parent 173422e9bc
commit e34e5cd6ab
4 changed files with 60 additions and 5 deletions
@@ -133,6 +133,19 @@ ImportColumn::make('sku')
If you require a column in the database, you also need to make sure that it has a [`rules(['required'])` validation rule](#validating-csv-data).
If a column is not mapped, it will not be validated since there is no data to validate.
If you allow an import to create records as well as [update existing ones](#updating-existing-records-when-importing), but only require a column to be mapped when creating records as it's a required field, you can use the `requiredMappingForNewRecordsOnly()` method instead of `requiredMapping()`:
```php
use Filament\Actions\Imports\ImportColumn;
ImportColumn::make('sku')
->requiredMappingForNewRecordsOnly()
```
If the `resolveRecord()` method returns a model instance that is not saved in the database yet, the column will be required to be mapped, just for that row. If the user does not map the column, and one of the rows in the import does not yet exist in the database, just that row will fail and a message will be added to the failed rows CSV after every row has been analyzed.
### Validating CSV data
You can call the `rules()` method to add validation rules to a column. These rules will check the data in each row from the CSV before it is saved to the database:
@@ -79,6 +79,7 @@ return [
'file_name' => 'import-:import_id-:csv_name-failed-rows',
'error_header' => 'error',
'system_error' => 'System error, please contact support.',
'column_mapping_required_for_new_record' => 'The :attribute column was not mapped to a column in the file, but it is required for creating new records.',
],
];
@@ -20,6 +20,8 @@ class ImportColumn extends Component
protected bool | Closure $isMappingRequired = false;
protected bool | Closure $isMappingRequiredForNewRecordsOnly = false;
protected int | Closure | null $decimalPlaces = null;
protected bool | Closure $isNumeric = false;
@@ -147,6 +149,13 @@ class ImportColumn extends Component
return $this;
}
public function requiredMappingForNewRecordsOnly(bool | Closure $condition = true): static
{
$this->isMappingRequiredForNewRecordsOnly = $condition;
return $this;
}
public function numeric(bool | Closure $condition = true, int | Closure | null $decimalPlaces = null): static
{
$this->isNumeric = $condition;
@@ -502,6 +511,11 @@ class ImportColumn extends Component
return (bool) $this->evaluate($this->isMappingRequired);
}
public function isMappingRequiredForNewRecordsOnly(): bool
{
return (bool) $this->evaluate($this->isMappingRequiredForNewRecordsOnly);
}
public function hasRelationship(): bool
{
return filled($this->getRelationshipName());
+32 -5
View File
@@ -56,6 +56,12 @@ abstract class Importer
return;
}
$recordExists = $this->record->exists;
if (! $recordExists) {
$this->checkColumnMappingRequirementsForNewRecords();
}
$this->callHook('beforeValidate');
$this->validateData();
$this->callHook('afterValidate');
@@ -64,8 +70,6 @@ abstract class Importer
$this->fillRecord();
$this->callHook('afterFill');
$recordExists = $this->record->exists;
$this->callHook('beforeSave');
$this->callHook($recordExists ? 'beforeUpdate' : 'beforeCreate');
$this->saveRecord();
@@ -96,6 +100,31 @@ abstract class Importer
$this->data = $data;
}
/**
* @throws ValidationException
*/
public function checkColumnMappingRequirementsForNewRecords(): void
{
foreach ($this->getCachedColumns() as $column) {
$columnName = $column->getName();
if (filled($this->columnMap[$columnName] ?? null)) {
continue;
}
if (! $column->isMappingRequiredForNewRecordsOnly()) {
continue;
}
Validator::validate(
data: [$columnName => null],
rules: [$columnName => ['required']],
messages: ["{$columnName}.required" => __('filament-actions::import.failure_csv.column_mapping_required_for_new_record')],
attributes: [$columnName => $column->getLabel()],
);
}
}
public function castData(): void
{
foreach ($this->getCachedColumns() as $column) {
@@ -125,14 +154,12 @@ abstract class Importer
*/
public function validateData(): void
{
$validator = Validator::make(
Validator::validate(
$this->data,
$this->getValidationRules(),
$this->getValidationMessages(),
$this->getValidationAttributes(),
);
$validator->validate();
}
/**