mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
feature: Required import mapping for new records only
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user