Skip to content

Commit

Permalink
feature: Required import mapping for new records only
Browse files Browse the repository at this point in the history
  • Loading branch information
danharrin committed Aug 12, 2024
1 parent 173422e commit e34e5cd
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 5 deletions.
13 changes: 13 additions & 0 deletions packages/actions/docs/07-prebuilt-actions/08-import.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions packages/actions/resources/lang/en/import.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
'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.',
],

];
14 changes: 14 additions & 0 deletions packages/actions/src/Imports/ImportColumn.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -147,6 +149,13 @@ public function requiredMapping(bool | Closure $condition = true): static
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;
Expand Down Expand Up @@ -502,6 +511,11 @@ public function isMappingRequired(): bool
return (bool) $this->evaluate($this->isMappingRequired);
}

public function isMappingRequiredForNewRecordsOnly(): bool
{
return (bool) $this->evaluate($this->isMappingRequiredForNewRecordsOnly);
}

public function hasRelationship(): bool
{
return filled($this->getRelationshipName());
Expand Down
37 changes: 32 additions & 5 deletions packages/actions/src/Imports/Importer.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ public function __invoke(array $data): void
return;
}

$recordExists = $this->record->exists;

if (! $recordExists) {
$this->checkColumnMappingRequirementsForNewRecords();
}

$this->callHook('beforeValidate');
$this->validateData();
$this->callHook('afterValidate');
Expand All @@ -64,8 +70,6 @@ public function __invoke(array $data): void
$this->fillRecord();
$this->callHook('afterFill');

$recordExists = $this->record->exists;

$this->callHook('beforeSave');
$this->callHook($recordExists ? 'beforeUpdate' : 'beforeCreate');
$this->saveRecord();
Expand Down Expand Up @@ -96,6 +100,31 @@ public function remapData(): void
$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) {
Expand Down Expand Up @@ -125,14 +154,12 @@ public function resolveRecord(): ?Model
*/
public function validateData(): void
{
$validator = Validator::make(
Validator::validate(
$this->data,
$this->getValidationRules(),
$this->getValidationMessages(),
$this->getValidationAttributes(),
);

$validator->validate();
}

/**
Expand Down

0 comments on commit e34e5cd

Please sign in to comment.