Skip to content

Commit

Permalink
Drop "Unique Field" option for term & user imports
Browse files Browse the repository at this point in the history
  • Loading branch information
duncanmcclean committed Dec 19, 2024
1 parent 9350434 commit c826e88
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 9 deletions.
2 changes: 1 addition & 1 deletion DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Before importing, you will need to do some preparation:
3. You can then map fields from your blueprint to fields/columns in your file.
* Depending on the fieldtype, some fields may have additional options, like "Related Key" or "Create when missing". You can read more about these below.
* Mapping is disabled for some fieldtypes, like the [Replicator fieldtype](https://statamic.dev/fieldtypes/replicator#content). If you wish to import these fields, you will need to build a [custom transformer](#transformers).
4. You will also need to specify a "Unique Field". This field will be used to determine if an item already exists in Statamic.
4. If you're importing entries, you will also need to specify a "Unique Field". This field will be used to determine if an entry already exists in Statamic.
5. Then, run the import and watch the magic happen! ✨

You can run the importer as many times as you like as you tweak the mappings. It'll update existing content and create new content as needed.
Expand Down
2 changes: 2 additions & 0 deletions lang/en/validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

return [
'file_type_not_allowed' => 'Only CSV and XML files can be imported at this time.',
'mappings_email_missing' => 'The Email field must be mapped on user imports.',
'mappings_not_provided' => 'You must map at least one field.',
'mappings_slug_missing' => 'The Slug field must be mapped on taxonomy imports.',
'site_not_configured_in_collection' => 'The chosen collection is not available on this site.',
'site_not_configured_in_taxonomy' => 'The chosen taxonomy is not available on this site.',
'unique_field_without_mapping' => 'Please configure a mapping for this field.',
Expand Down
1 change: 1 addition & 0 deletions src/Fieldtypes/ImportMappingsFieldtype.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public function extraRules(): array

return collect($this->field->value())
->reject(fn ($row) => empty($row['key']))
->filter(fn ($row) => $fields->has($row['key']))
->flatMap(function (array $row, string $field) use ($fields) {
$rules = $fields
->get($field)
Expand Down
19 changes: 16 additions & 3 deletions src/Imports/Blueprint.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,19 @@ function (string $attribute, mixed $value, Closure $fail) {
'required',
'array',
function (string $attribute, mixed $value, Closure $fail) {
$type = Arr::get(request()->destination, 'type');

if (collect($value)->reject(fn (array $mapping) => empty($mapping['key']))->isEmpty()) {
$fail('importer::validation.mappings_not_provided')->translate();
}

if ($type === 'terms' && Arr::get($value, 'slug.key') === null) {
$fail('importer::validation.mappings_slug_missing')->translate();
}

if ($type === 'users' && Arr::get($value, 'email.key') === null) {
$fail('importer::validation.mappings_email_missing')->translate();
}
},
],
'if' => $import ? static::buildFieldConditions($import) : null,
Expand All @@ -213,19 +223,22 @@ function (string $attribute, mixed $value, Closure $fail) {
'type' => 'radio',
'display' => __('Unique Field'),
'instructions' => __('importer::messages.unique_field_instructions'),
'options' => $import?->destinationBlueprint()->fields()->all()
'options' => $import?->mappingFields()->all()
->filter(fn ($field) => in_array($field->type(), ['text', 'integer', 'slug']))
->map(fn ($field) => ['key' => $field->handle(), 'value' => $field->display()])
->values(),
'validate' => [
'required',
'required_if:destination.type,entries',
function (string $attribute, mixed $value, Closure $fail) {
if (! collect(request()->mappings)->reject(fn ($mapping) => empty($mapping['key']))->has($value)) {
$fail('importer::validation.unique_field_without_mapping')->translate();
}
},
],
'if' => $import ? static::buildFieldConditions($import) : null,
'if' => [
'destination.type' => 'entries',
],
// 'if' => $import ? static::buildFieldConditions($import) : null,
],
],
],
Expand Down
6 changes: 2 additions & 4 deletions src/Jobs/ImportItemJob.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ protected function findOrCreateEntry(array $data): void
protected function findOrCreateTerm(array $data): void
{
$term = Term::query()
->where('slug', $data['slug'])
->where('taxonomy', $this->import->get('destination.taxonomy'))
->where($this->import->get('unique_field'), $data[$this->import->get('unique_field')])
->first();

if (! $term) {
Expand Down Expand Up @@ -153,9 +153,7 @@ protected function findOrCreateTerm(array $data): void

protected function findOrCreateUser(array $data): void
{
$user = User::query()
->where($this->import->get('unique_field'), $data[$this->import->get('unique_field')])
->first();
$user = User::findByEmail($data['email']);

if (! $user) {
if (! in_array('create', $this->import->get('strategy'))) {
Expand Down
52 changes: 51 additions & 1 deletion tests/Imports/UpdateImportTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Support\Facades\Storage;
use PHPUnit\Framework\Attributes\Test;
use Statamic\Facades\Collection;
use Statamic\Facades\Taxonomy;
use Statamic\Facades\User;
use Statamic\Importer\Facades\Import;
use Statamic\Importer\Tests\TestCase;
Expand Down Expand Up @@ -224,7 +225,56 @@ public function validation_error_is_thrown_without_any_mappings()
}

#[Test]
public function throws_validation_errors_for_mapping_fields()
public function validation_error_is_thrown_for_terms_import_without_slug_mapping()
{
Taxonomy::make('tags')->save();

$this
->actingAs(User::make()->makeSuper()->save())
->patch("/cp/utilities/importer/{$this->import->id()}", [
'name' => 'Posts',
'file' => ['posts.csv'],
'destination' => ['type' => 'terms', 'taxonomy' => ['tags'], 'blueprint' => 'tag'],
'strategy' => ['create', 'update'],
'mappings' => [
'title' => ['key' => 'Title'],
'slug' => ['key' => null],
],
])
->assertSessionHasErrors('mappings');
}

#[Test]
public function validation_error_is_thrown_for_users_import_without_email_mapping()
{
User::blueprint()->setContents([
'sections' => [
'main' => [
'fields' => [
['handle' => 'name', 'field' => ['type' => 'text']],
['handle' => 'email', 'field' => ['type' => 'text']],
],
],
],
]);

$this
->actingAs(User::make()->makeSuper()->save())
->patch("/cp/utilities/importer/{$this->import->id()}", [
'name' => 'Posts',
'file' => ['posts.csv'],
'destination' => ['type' => 'users'],
'strategy' => ['create', 'update'],
'mappings' => [
'name' => ['key' => 'Name'],
'email' => ['key' => null],
],
])
->assertSessionHasErrors('mappings');
}

#[Test]
public function validation_errors_are_thrown_for_transformer_fields()
{
$this
->actingAs(User::make()->makeSuper()->save())
Expand Down

0 comments on commit c826e88

Please sign in to comment.