added dateformat and timezone options to project importer (#2042)
This commit is contained in:
@@ -14,6 +14,7 @@ use App\Importer\ImporterService;
|
|||||||
use App\Importer\ImportNotFoundException;
|
use App\Importer\ImportNotFoundException;
|
||||||
use App\Repository\TeamRepository;
|
use App\Repository\TeamRepository;
|
||||||
use App\Repository\UserRepository;
|
use App\Repository\UserRepository;
|
||||||
|
use App\Validator\ValidationFailedException;
|
||||||
use Symfony\Component\Console\Command\Command;
|
use Symfony\Component\Console\Command\Command;
|
||||||
use Symfony\Component\Console\Helper\ProgressBar;
|
use Symfony\Component\Console\Helper\ProgressBar;
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
use Symfony\Component\Console\Input\InputArgument;
|
||||||
@@ -56,6 +57,8 @@ class ImportProjectCommand extends Command
|
|||||||
->addOption('reader', null, InputOption::VALUE_REQUIRED, 'The reader to use (supported: csv, csv-semicolon)', 'csv')
|
->addOption('reader', null, InputOption::VALUE_REQUIRED, 'The reader to use (supported: csv, csv-semicolon)', 'csv')
|
||||||
->addOption('teamlead', null, InputOption::VALUE_REQUIRED, 'If you want to create empty teams for each project, give the username of the teamlead to be assigned')
|
->addOption('teamlead', null, InputOption::VALUE_REQUIRED, 'If you want to create empty teams for each project, give the username of the teamlead to be assigned')
|
||||||
->addOption('no-update', null, InputOption::VALUE_NONE, 'If you want to create new project, but not update existing ones')
|
->addOption('no-update', null, InputOption::VALUE_NONE, 'If you want to create new project, but not update existing ones')
|
||||||
|
->addOption('date-format', null, InputOption::VALUE_REQUIRED, 'Date format for imports', 'Y-m-d')
|
||||||
|
->addOption('timezone', null, InputOption::VALUE_REQUIRED, 'Timezone for imports', date_default_timezone_get())
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,9 +128,17 @@ class ImportProjectCommand extends Command
|
|||||||
|
|
||||||
$progressBar = new ProgressBar($output, $amount);
|
$progressBar = new ProgressBar($output, $amount);
|
||||||
|
|
||||||
|
$options = [];
|
||||||
|
if (null !== ($dateFormat = $input->getOption('date-format'))) {
|
||||||
|
$options['dateformat'] = $dateFormat;
|
||||||
|
}
|
||||||
|
if (null !== ($timezone = $input->getOption('timezone'))) {
|
||||||
|
$options['timezone'] = $timezone;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($records as $record) {
|
foreach ($records as $record) {
|
||||||
try {
|
try {
|
||||||
$projects[] = $importer->convertEntryToProject($record);
|
$projects[] = $importer->convertEntryToProject($record, $options);
|
||||||
} catch (\Exception $ex) {
|
} catch (\Exception $ex) {
|
||||||
$io->error(sprintf('Invalid row %s: %s', $row, $ex->getMessage()));
|
$io->error(sprintf('Invalid row %s: %s', $row, $ex->getMessage()));
|
||||||
$doImport = false;
|
$doImport = false;
|
||||||
@@ -158,7 +169,6 @@ class ImportProjectCommand extends Command
|
|||||||
$progressBar = new ProgressBar($output, $amount);
|
$progressBar = new ProgressBar($output, $amount);
|
||||||
|
|
||||||
foreach ($projects as $project) {
|
foreach ($projects as $project) {
|
||||||
$row++;
|
|
||||||
$progressBar->advance();
|
$progressBar->advance();
|
||||||
try {
|
try {
|
||||||
if ($project->getCustomer()->getId() === null) {
|
if ($project->getCustomer()->getId() === null) {
|
||||||
@@ -194,8 +204,16 @@ class ImportProjectCommand extends Command
|
|||||||
|
|
||||||
$this->teams->saveTeam($team);
|
$this->teams->saveTeam($team);
|
||||||
$createdTeams++;
|
$createdTeams++;
|
||||||
|
} catch (ValidationFailedException $ex) {
|
||||||
|
$io->error(sprintf('Failed importing project "%s" with: %s', $project->getName(), $ex->getMessage()));
|
||||||
|
for ($i = 0; $i < $ex->getViolations()->count(); $i++) {
|
||||||
|
$violation = $ex->getViolations()->get($i);
|
||||||
|
$io->error(sprintf('Failed validating field "%s" with value "%s": %s', $violation->getPropertyPath(), $violation->getInvalidValue(), $violation->getMessage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 4;
|
||||||
} catch (\Exception $ex) {
|
} catch (\Exception $ex) {
|
||||||
$io->error(sprintf('Failed importing project row %s with: %s', $row, $ex->getMessage()));
|
$io->error(sprintf('Failed importing project "%s" with: %s', $project->getName(), $ex->getMessage()));
|
||||||
|
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,11 +39,11 @@ abstract class AbstractProjectImporter implements ProjectImporterInterface
|
|||||||
return $this->customerService->findCustomerByName($name);
|
return $this->customerService->findCustomerByName($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function convertEntryToProject(array $entry): Project
|
public function convertEntryToProject(array $entry, array $options = []): Project
|
||||||
{
|
{
|
||||||
$project = $this->findProject($entry);
|
$project = $this->findProject($entry);
|
||||||
|
|
||||||
$this->convertEntry($project, $entry);
|
$this->convertEntry($project, $entry, $options);
|
||||||
|
|
||||||
return $project;
|
return $project;
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ abstract class AbstractProjectImporter implements ProjectImporterInterface
|
|||||||
if ($customer->getId() !== $project->getCustomer()->getId()) {
|
if ($customer->getId() !== $project->getCustomer()->getId()) {
|
||||||
throw new \InvalidArgumentException(
|
throw new \InvalidArgumentException(
|
||||||
sprintf(
|
sprintf(
|
||||||
'Customer mismatch for project %s with attached customer %s and new customer %s',
|
'Customer mismatch for project "%s" with attached customer "%s" and new customer "%s"',
|
||||||
$project->getName(),
|
$project->getName(),
|
||||||
$project->getCustomer()->getName(),
|
$project->getCustomer()->getName(),
|
||||||
$customer->getName()
|
$customer->getName()
|
||||||
@@ -84,7 +84,10 @@ abstract class AbstractProjectImporter implements ProjectImporterInterface
|
|||||||
|
|
||||||
private function findCustomer(string $customerName): Customer
|
private function findCustomer(string $customerName): Customer
|
||||||
{
|
{
|
||||||
if (!\array_key_exists($customerName, $this->customerCache)) {
|
$customerName = trim($customerName);
|
||||||
|
$key = strtolower($customerName);
|
||||||
|
|
||||||
|
if (!\array_key_exists($key, $this->customerCache)) {
|
||||||
$customer = $this->findCustomerByName($customerName);
|
$customer = $this->findCustomerByName($customerName);
|
||||||
|
|
||||||
if ($customer === null) {
|
if ($customer === null) {
|
||||||
@@ -92,10 +95,10 @@ abstract class AbstractProjectImporter implements ProjectImporterInterface
|
|||||||
$customer->setName($customerName);
|
$customer->setName($customerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->customerCache[$customerName] = $customer;
|
$this->customerCache[$key] = $customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->customerCache[$customerName];
|
return $this->customerCache[$key];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -152,7 +155,8 @@ abstract class AbstractProjectImporter implements ProjectImporterInterface
|
|||||||
*
|
*
|
||||||
* @param Project $project
|
* @param Project $project
|
||||||
* @param array $entry
|
* @param array $entry
|
||||||
* @return mixed
|
* @param array $options
|
||||||
|
* @return void
|
||||||
*/
|
*/
|
||||||
abstract protected function convertEntry(Project $project, array $entry);
|
abstract protected function convertEntry(Project $project, array $entry, array $options = []): void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use App\Entity\ProjectMeta;
|
|||||||
|
|
||||||
final class DefaultProjectImporter extends AbstractProjectImporter
|
final class DefaultProjectImporter extends AbstractProjectImporter
|
||||||
{
|
{
|
||||||
protected function convertEntry(Project $project, array $row)
|
protected function convertEntry(Project $project, array $row, array $options = []): void
|
||||||
{
|
{
|
||||||
foreach ($row as $name => $value) {
|
foreach ($row as $name => $value) {
|
||||||
switch (strtolower($name)) {
|
switch (strtolower($name)) {
|
||||||
@@ -33,7 +33,7 @@ final class DefaultProjectImporter extends AbstractProjectImporter
|
|||||||
case 'order-number':
|
case 'order-number':
|
||||||
case 'order number':
|
case 'order number':
|
||||||
if (!empty($value)) {
|
if (!empty($value)) {
|
||||||
$project->setOrderNumber($value);
|
$project->setOrderNumber(substr($value, 0, 20));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -42,8 +42,20 @@ final class DefaultProjectImporter extends AbstractProjectImporter
|
|||||||
case 'order date':
|
case 'order date':
|
||||||
if (!empty($value)) {
|
if (!empty($value)) {
|
||||||
$timezone = $project->getCustomer()->getTimezone();
|
$timezone = $project->getCustomer()->getTimezone();
|
||||||
|
if (isset($options['timezone'])) {
|
||||||
|
$timezone = $options['timezone'];
|
||||||
|
}
|
||||||
$timezone = new \DateTimeZone($timezone ?? date_default_timezone_get());
|
$timezone = new \DateTimeZone($timezone ?? date_default_timezone_get());
|
||||||
$project->setOrderDate(new \DateTime($value, $timezone));
|
if (isset($options['dateformat'])) {
|
||||||
|
$date = \DateTime::createFromFormat($options['dateformat'], $value, $timezone);
|
||||||
|
} else {
|
||||||
|
$date = new \DateTime($value, $timezone);
|
||||||
|
}
|
||||||
|
if ($date instanceof \DateTime) {
|
||||||
|
$project->setOrderDate($date);
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('Invalid order date: ' . $value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -84,7 +96,5 @@ final class DefaultProjectImporter extends AbstractProjectImporter
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $project;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,13 @@ use App\Entity\Project;
|
|||||||
|
|
||||||
interface ProjectImporterInterface
|
interface ProjectImporterInterface
|
||||||
{
|
{
|
||||||
public function convertEntryToProject(array $entry): Project;
|
/**
|
||||||
|
* Convert an entry (key-value pairs) to a Project entity.
|
||||||
|
* Accepts an optional array of options (like "dateformat" or "timezone").
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $entry
|
||||||
|
* @param array<string, mixed> $options
|
||||||
|
* @return Project
|
||||||
|
*/
|
||||||
|
public function convertEntryToProject(array $entry, array $options = []): Project;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user