Я хочу импортировать файл .csv с такими заголовками, как имя, адрес электронной почты и т. д. Как часть функции слияния почты в нашем веб-приложении (мы используем Symfony 3.4). До сих пор мне удалось сохранить файл .csv в базе данных с помощью Doctrine, когда я знаю, какими будут заголовки в .csv. Мне также нужно предоставить пользователю возможность изменять заголовок столбцов в случае, если заголовки отличаются или автоматическое сопоставление при импорте не работает.
Является ли здесь лучшим вариантом сохранить информацию в базе данных, а затем переместить данные с помощью Doctrine, или есть какой-то способ дать пользователю возможность сопоставить столбцы перед сохранением? Я относительно новичок как в Symfony, так и в Doctrine, поэтому не вижу решения.
Вот код контроллера:
public function usersListUploadAction(Request $request) {
// grab uploaded .csv file
$file = $_FILES["file"]["tmp_name"];
$fileimplode = implode("/", $file);
// convert .csv if made on mac
if (!ini_get("auto_detect_line_endings")) {
ini_set("auto_detect_line_endings", '1');
}
// create associative array from .csv
$reader = Reader::createFromPath($fileimplode);
$addedUsers = $reader->fetchAssoc();
$em = $this->getDoctrine()->getManager();
foreach($addedUsers as $row) {
// check for existing users
$emailAddress = $row["Email Address"];
$user = $this->get('manager_user.repository')->findByEmailAddressWithoutParents($emailAddress);
if ($user === []) {
// create new user
$userTypeId = 1;
$role = $request->get('roles', []);
$firstname = $row["First Name"];
$surname = $row["Last Name"];
$email = $row["Email Address"];
$username = (strtolower($row["First Name"].".".$row["Last Name"]));
$phone = null;
$userBuilder = $this->get('manager_user.manager')->newUser(
$userTypeId,
$username,
$phone,
$email,
$role,
$password = null,
$organisation = null,
$emailResetPasswordLink = 0,
$firstname,
$surname,
$name = null,
$roles = []
);
$user = $userBuilder;
// add email to contact_methods
$cmType = $this->get('manager_user_contact_method_type.repository')->find(ContactMethodTypeInterface::EMAIL);
$cmEmail = $this->get('manager_user_contact_method.builder')->createNew($cmType, $row["Email Address"], $user, 1);
$em->persist($userBuilder);
$em->persist($cmEmail);
}
$em->flush();
}
// return to user list page with list updated from .csv users
$listId = $request->get('listId');
$list = $this->get('manager.email.list_repository')->find($listId);
$status = 1;
//loop over the added users
foreach($addedUsers as $row) {
$userNameLower = (strtolower($row["First Name"].".".$row["Last Name"]));
$userId = strval($this->get('manager_user.repository')->getUserIdByUserName($userNameLower));
$user = $this->get('manager_user.repository')->find($userId);
if (!$user->isInList($list)) { //this user is not in the list already so add it
$dateSubscribed = new \DateTime();
$emailCampaignListUser = new EmailCampaignListUser($user, $list, $dateSubscribed, $status);
$em->persist($emailCampaignListUser);
}
}
$em->flush();
return $this->redirectToRoute('manager_email_campaign_lists_users_upload_check', array('listId' => 1));
}
Привет, Александр, не могли бы вы подробнее рассказать, как этого добиться?






Приведу пример (не полный). Как я уже говорил, вы можете так поступать.
Для первый шаг вы можете выбрать желаемое решение для внешнего интерфейса, например Drag & Drop.
На мой взгляд, вы должны определить свои ключи
//this is your code
//Here we define that "firstname" is your key for the first name
$fields = ["firstname","lastname"];
Вторая часть первого шага - получение заголовка CSV с использованием fgetcsv в первой строке (строке заголовка).
if (($handle = fopen("yourcsv.csv", "r")) !== FALSE) {
//Here you get all csv headers
$header = fgetcsv($handle, 1000, ",");
fclose($handle);
}
На этом этапе после того, как вы (или пользователь) выполнили сопоставление, вы можете сохранить сопоставление в базе данных, если это действительно необходимо, или просто использовать POST для получения сопоставления на втором этапе.
Второй шаг мы анализируем файл csv, пропуская первую строку, и используем ранее выполненное сопоставление для правильного получения данных.
//Your mapping is stored in $mapping by example
//it contains "fieldname" => "csv index" example "firstname" => 3
if (($handle = fopen("test.csv", "r")) !== FALSE) {
//skip header line here
fgetcsv($handle, 1000, ",");
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
//$data contain each user data
$userBuilder = $this->get('manager_user.manager')->newUser(
$data[$mapping['firstname']],
$data[$mapping['lastname']],
//etc...
);
}
fclose($handle);
}
Надеюсь, это поможет и прояснится.
Функция сопоставления - хорошая идея, но подразумевает, что перед импортом нужно сделать еще один шаг. Вы можете легко сделать это, указав ожидаемые поля и распечатав заголовки csv.