Skip to content

Commit e2da939

Browse files
committed
allow preset id
1 parent 02a010a commit e2da939

File tree

9 files changed

+115
-71
lines changed

9 files changed

+115
-71
lines changed

README.md

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Importing entities with preview and edit features for Symfony.
3737
* [Controller-specific templates](#controller-specific-templates)
3838
* [Main layout](#main-layout)
3939
* [Additional data](#additional-data)
40+
* [Updating entities](#updating-entities)
4041
* [Importing data to array field](#importing-data-to-array-field)
4142
* [Full example of CSV file](#full-example-of-csv-file)
4243

@@ -360,6 +361,25 @@ protected function prepareMatrixEditView(FormInterface $form, Matrix $matrix, bo
360361
}
361362
```
362363

364+
## Updating entities
365+
366+
If you want to update your entities:
367+
- Set `allowOverrideEntity` to `true` in your import configuration file.
368+
- Then in your import file:
369+
- Add `entity_id` in header and:
370+
- Add entity ID to row
371+
- Leave it empty (if you want to set it manually or import it as new record)
372+
- Or if you don't want to add `entity_id` header, you can still manually set each entity to override.
373+
374+
#### CSV file
375+
376+
```csv
377+
entity_id,user_name
378+
2,user_1
379+
,user_2
380+
10,user_3
381+
```
382+
363383
## Importing data to array field
364384

365385
If your entity has an array field, and you want to import data from CSV file to it, this is how you can do it.
@@ -434,8 +454,8 @@ user_3,SUPER_ADMIN
434454
## Full example of CSV file
435455

436456
```csv
437-
user_name,age,email,roles,country:en,name:pl
438-
user_1,21,user_1@test.com,USER&ADMIN&SUPER_ADMIN,Poland,Polska
439-
user_2,34,user_2@test.com,USER,England,Anglia
440-
user_3,56,user_3@test.com,SUPER_ADMIN,Germany,Niemcy
457+
entity_id,user_name,age,email,roles,country:en,name:pl
458+
1,user_1,21,user_1@test.com,USER&ADMIN&SUPER_ADMIN,Poland,Polska
459+
3, user_2,34,user_2@test.com,USER,England,Anglia
460+
,user_3,56,user_3@test.com,SUPER_ADMIN,Germany,Niemcy
441461
```

UPGRADE.md

Lines changed: 33 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,15 @@
1-
UPGRADE TO 3.6
2-
=======================
1+
# UPGRADE TO 3.7
32

4-
Import data to array
5-
--------------
3+
### Preset entity id before updating - [go to the documentation](README.md#updating-entities)
64

7-
* By default, allowed file extensions are set to `'csv', 'xls', 'xlsx', 'ods'`.
8-
However, if you want to change it, you can override this method in your import configuration.
5+
# UPGRADE TO 3.6
96

10-
```php
11-
public function getAllowedFileExtensions(): array
12-
{
13-
return ['csv', 'xls', 'xlsx', 'ods'];
14-
}
15-
```
7+
### Import data to array - [go to the documentation](README.md#importing-data-to-array-field)
168

17-
UPGRADE TO 3.5
18-
=======================
9+
# UPGRADE TO 3.5
1910

20-
Import data to array
21-
--------------
22-
* If your entity has an array field, and you want to import data from CSV file to it, it is now possible.
11+
## Import data to array
12+
- If your entity has an array field, and you want to import data from CSV file to it, it is now possible.
2313

2414
```php
2515
use JG\BatchEntityImportBundle\Form\Type\ArrayTextType;
@@ -39,32 +29,25 @@ public function getFieldsDefinitions(): array
3929
```
4030

4131

42-
UPGRADE TO 3.1
43-
=======================
32+
# UPGRADE TO 3.1
4433

45-
CSV File
46-
--------------
47-
* Now CSV file can contain spaces and dashes as a header name, for example "my column name" or "my-column-name".
34+
## CSV File
35+
- Now CSV file can contain spaces and dashes as a header name, for example "my column name" or "my-column-name".
4836

49-
Import Configuration class
50-
--------------
51-
* When header name contains spaces we should use underscores instead of spaces when defining fields names in fields definitions and in constraints.
37+
## Import Configuration class
38+
- When header name contains spaces we should use underscores instead of spaces when defining fields names in fields definitions and in constraints.
5239

5340

54-
UPGRADE TO 3.0
55-
=======================
41+
# UPGRADE TO 3.0
5642

57-
Controller
58-
--------------
43+
## Controller
5944
* Passing configuration class by `getSubscribedServices()` was removed. Now it is only possible by autoconfiguration.
6045

6146

62-
UPGRADE TO 2.5
63-
=======================
47+
# UPGRADE TO 2.5
6448

65-
Import Configuration class
66-
--------------
67-
* Added new validator to check matrix record data uniqueness in database.
49+
## Import Configuration class
50+
- Added new validator to check matrix record data uniqueness in database.
6851
```php
6952
use JG\BatchEntityImportBundle\Validator\Constraints\DatabaseEntityUnique;
7053

@@ -76,12 +59,10 @@ public function getMatrixConstraints(): array
7659
}
7760
```
7861

79-
UPGRADE TO 2.4
80-
=======================
62+
# UPGRADE TO 2.4
8163

82-
Import Configuration class
83-
--------------
84-
* Added new validator to check matrix record data uniqueness.
64+
## Import Configuration class
65+
- Added new validator to check matrix record data uniqueness.
8566
```php
8667
use JG\BatchEntityImportBundle\Validator\Constraints\MatrixRecordUnique;
8768

@@ -93,33 +74,27 @@ public function getMatrixConstraints(): array
9374
}
9475
```
9576

96-
Controller
97-
--------------
98-
* List of options passed to form in `createMatrixForm()` method, should contain new `constraints` element:
77+
## Controller
78+
- List of options passed to form in `createMatrixForm()` method, should contain new `constraints` element:
9979
`'constraints' => $importConfiguration->getMatrixConstraints()`
10080

101-
UPGRADE TO 2.3
102-
=======================
81+
# UPGRADE TO 2.3
10382

104-
Controller
105-
--------------
106-
* Passing configuration class by `getSubscribedServices()` method is not needed anymore and will be removed in the future.
107-
* To make sure that configuration class will be injected automatically:
108-
* Interface `JG\BatchEntityImportBundle\Controller\ImportConfigurationAutoInjectInterface` should be implemented.
109-
* Trait `JG\BatchEntityImportBundle\Controller\ImportConfigurationAutoInjectTrait` should be used to add needed methods.
83+
## Controller
84+
- Passing configuration class by `getSubscribedServices()` method is not needed anymore and will be removed in the future.
85+
- To make sure that configuration class will be injected automatically:
86+
- Interface `JG\BatchEntityImportBundle\Controller\ImportConfigurationAutoInjectInterface` should be implemented.
87+
- Trait `JG\BatchEntityImportBundle\Controller\ImportConfigurationAutoInjectTrait` should be used to add needed methods.
11088

11189

112-
UPGRADE TO 2.2
113-
=======================
90+
# UPGRADE TO 2.2
11491

115-
Import Configuration class
116-
--------------
117-
* Now configuration class should be always registered as a service:
92+
## Import Configuration class
93+
- Now configuration class should be always registered as a service:
11894
```yaml
11995
services:
12096
App\Model\ImportConfiguration\UserImportConfiguration: ~
12197
```
12298
123-
Controller
124-
--------------
125-
* Entity Manager is no longer passed as an argument of actions.
99+
## Controller
100+
- Entity Manager is no longer passed as an argument of actions.

src/Controller/BaseImportControllerTrait.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ protected function prepareMatrixEditView(FormInterface $form, Matrix $matrix, bo
8989
$this->getMatrixEditTemplateName(),
9090
[
9191
'header_info' => $matrix->getHeaderInfo($configuration->getEntityClassName()),
92-
'data' => $matrix->getRecords(),
9392
'form' => $form->createView(),
9493
'importConfiguration' => $configuration,
9594
]

src/Form/Type/MatrixRecordType.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
use Symfony\Component\Form\FormBuilderInterface;
2020
use Symfony\Component\Form\FormEvent;
2121
use Symfony\Component\Form\FormEvents;
22+
use Symfony\Component\Form\FormInterface;
23+
use Symfony\Component\Form\FormView;
2224
use Symfony\Component\OptionsResolver\Exception\AccessException;
2325
use Symfony\Component\OptionsResolver\Exception\UndefinedOptionsException;
2426
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -101,4 +103,17 @@ private function addField(array $fieldDefinitions, string $columnName, FormEvent
101103
? $event->getForm()->add($columnName, $definition->getClass(), $definition->getOptions())
102104
: $event->getForm()->add($columnName, TextType::class);
103105
}
106+
107+
public function finishView(FormView $view, FormInterface $form, array $options): void
108+
{
109+
/** @var MatrixRecord $entity */
110+
$entity = $form->getData();
111+
$selectedValue = $entity->entityId;
112+
113+
foreach ($view['entity']->vars['choices'] ?? [] as $index => $choice) {
114+
if ($choice->value === $selectedValue) {
115+
$view['entity']->vars['choices'][$index]->attr['selected'] = 'selected';
116+
}
117+
}
118+
}
104119
}

src/Model/Matrix/Matrix.php

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
class Matrix
1313
{
1414
private const RESERVED_ENTITY_COLUMN_NAME = 'entity';
15+
private const RESERVED_ENTITY_ID_COLUMN_NAME = 'entity_id';
1516
#[Assert\All([
1617
new Assert\NotBlank(),
1718
new Assert\Type('string'),
@@ -33,9 +34,9 @@ public function __construct(array $header = [], array $recordsData = [])
3334
$this->header = $this->clearHeader($header);
3435

3536
foreach ($recordsData as $data) {
36-
$data = $this->clearRecordData($data);
37-
if ($data) {
38-
$this->records[] = new MatrixRecord($data);
37+
$clearedData = $this->clearRecordData($data);
38+
if ($clearedData) {
39+
$this->records[] = new MatrixRecord($clearedData, $this->getEntityIdValue($data));
3940
}
4041
}
4142
}
@@ -65,6 +66,17 @@ public function getHeaderInfo(string $className): array
6566
return $info;
6667
}
6768

69+
private function getEntityIdValue(array $data): int|string|null
70+
{
71+
foreach ($data as $name => $value) {
72+
if (self::RESERVED_ENTITY_ID_COLUMN_NAME === $name) {
73+
return $value;
74+
}
75+
}
76+
77+
return null;
78+
}
79+
6880
private function clearHeader(array $header): array
6981
{
7082
$header = array_values(
@@ -81,6 +93,6 @@ private function clearRecordData(array $data): array
8193

8294
private function isColumnNameValid(?string $name): bool
8395
{
84-
return !empty(trim((string) $name)) && self::RESERVED_ENTITY_COLUMN_NAME !== $name;
96+
return !empty(trim((string) $name)) && !\in_array($name, [self::RESERVED_ENTITY_COLUMN_NAME, self::RESERVED_ENTITY_ID_COLUMN_NAME], true);
8597
}
8698
}

src/Model/Matrix/MatrixFactory.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use JG\BatchEntityImportBundle\Service\CsvDelimiterDetector;
99
use PhpOffice\PhpSpreadsheet\Reader\BaseReader;
1010
use PhpOffice\PhpSpreadsheet\Reader\Csv;
11+
use PhpOffice\PhpSpreadsheet\Reader\Xls;
1112
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
1213
use Symfony\Component\HttpFoundation\File\UploadedFile;
1314

@@ -55,7 +56,7 @@ private static function getReader(UploadedFile $file): BaseReader
5556
if ($reader instanceof Csv) {
5657
$detectedDelimiter = (new CsvDelimiterDetector())->detect($file->getContent());
5758
$reader->setDelimiter($detectedDelimiter->value);
58-
} elseif ($reader instanceof Xlsx) {
59+
} elseif ($reader instanceof Xls || $reader instanceof Xlsx) {
5960
$reader->setIgnoreRowsWithNoCells(true);
6061
}
6162

src/Model/Matrix/MatrixRecord.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class MatrixRecord
99
private ?object $entity = null;
1010
private array $data = [];
1111

12-
public function __construct(array $data = [])
12+
public function __construct(array $data = [], public readonly int|string|null $entityId = null)
1313
{
1414
foreach ($data as $name => $value) {
1515
if (!empty(\trim((string) $name))) {

tests/Controller/ImportControllerTraitTest.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,28 @@ public function testUpdateExistingRecord(
6666
$this->assertEntityValues($expectedDefaultValues, $updatedEntityId);
6767

6868
$this->submitSelectFileForm(__DIR__ . '/../Fixtures/Resources/test_updated_data.csv');
69+
70+
$this->assertSame(
71+
'2',
72+
$this->client->getCrawler()->filterXpath('//select[@name="matrix[records][0][entity]"]/option[@selected]')->attr('value'),
73+
);
74+
$this->assertSame(
75+
'test',
76+
$this->client->getCrawler()->filterXpath('//input[@name="matrix[records][0][test_private_property]"]')->attr('value')
77+
);
78+
$this->assertSame(
79+
'lorem ipsum',
80+
$this->client->getCrawler()->filterXpath('//input[@name="matrix[records][0][test-private-property2]"]')->attr('value')
81+
);
82+
$this->assertSame(
83+
'qwerty',
84+
$this->client->getCrawler()->filterXpath('//input[@name="matrix[records][0][test_public_property]"]')->attr('value')
85+
);
86+
$this->assertSame(
87+
'arr_val_1000|array_val_1001',
88+
$this->client->getCrawler()->filterXpath('//input[@name="matrix[records][0][test_array_field]"]')->attr('value')
89+
);
90+
6991
$this->client->submitForm('btn-submit', [
7092
'matrix' => [
7193
'records' => [
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
test_private_property,test-private-property2,test public property,test_array_field
2-
test,lorem ipsum,qwerty,arr_val_1000|array_val_1001
1+
test_private_property,test-private-property2,test public property,test_array_field,entity_id
2+
test,lorem ipsum,qwerty,arr_val_1000|array_val_1001,2

0 commit comments

Comments
 (0)