<?php declare(strict_types=1);
namespace Acris\Countries;
use Doctrine\DBAL\DBALException;
use Shopware\Core\Framework\DataAbstractionLayer\Search\EntitySearchResult;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\ContainsFilter;
use Shopware\Core\Framework\Plugin;
use Shopware\Core\Framework\Plugin\Context\UninstallContext;
use Shopware\Core\Framework\Plugin\Context\InstallContext;
use Shopware\Core\Framework\Plugin\Context\UpdateContext;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\EntityRepositoryInterface;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Doctrine\DBAL\Connection;
use Shopware\Core\System\Country\CountryEntity;
use Shopware\Core\System\Language\LanguageEntity;
class AcrisCountriesCS extends Plugin
{
const COUNTRY_LOCALES_CSV_DATA_MATCH = [
[
'locales' => [
'en-AS', 'en-AU', 'en-BE', 'en-BW', 'en-BZ', 'en-CA', 'en-GB', 'en-GU', 'en-HK',
'en-IE', 'en-IN', 'en-JM', 'en-MH', 'en-MP', 'en-MT', 'en-NA', 'en-NZ', 'en-PH',
'en-PK', 'en-SG', 'en-TT', 'en-UM', 'en-US', 'en-VI', 'en-ZA', 'en-ZW'
],
'name' => 4,
'acris_countries_regex_description' => 16
],
[
'locales' => [
'de-AT', 'de-BE', 'de-CH', 'de-DE', 'de-LI', 'de-LU'
],
'name' => 1,
'acris_countries_regex_description' => 15
],
[
'locales' => [
'fr-BE', 'fr-CA', 'fr-CH', 'fr-FR', 'fr-LU', 'fr-MC', 'fr-SN'
],
'name' => 17,
'acris_countries_regex_description' => 18
],
[
'locales' => [
'it-CH', 'it-IT'
],
'name' => 19,
'acris_countries_regex_description' => 20
],
[
'locales' => [
'es-AR', 'es-BO', 'es-CL', 'es-CO', 'es-CR', 'es-DO', 'es-EC', 'es-ES', 'es-GT',
'es-HN', 'es-MX', 'es-NI', 'es-PA', 'es-PE', 'es-PR', 'es-PY', 'es-SV', 'es-US',
'es-UY', 'es-VE'
],
'name' => 21,
'acris_countries_regex_description' => 22
]
];
private $csvData = array();
public function update(UpdateContext $context): void
{
$this->readData();
$this->insertCountryData($context->getContext());
}
public function install(InstallContext $context): void
{
$this->readData();
$this->insertCountryData($context->getContext());
}
private function getAvailableLocales(Context $context)
{
/** @var EntitySearchResult $languagesSearchResult */
$languagesSearchResult = $this->container->get('language.repository')->search((new Criteria())->addAssociation('locale'), $context);
$locales = [];
/** @var LanguageEntity $languageEntity */
foreach ($languagesSearchResult->getElements() as $languageEntity) {
$locales[] = $languageEntity->getLocale()->getCode();
}
array_unique($locales);
return $locales;
}
private function readData(): void
{
$file = $this->getPath() . "/Components/Resources/acris_country_list.csv";
$handle = fopen($file, "r");
if (empty($handle) === false) {
while (($data = fgetcsv($handle, 1000, ";")) !== FALSE) {
$this->csvData[] = $data;
}
fclose($handle);
}
}
private function insertCountryData(Context $context): void
{
/** @var EntityRepositoryInterface $countryRepository */
$countryRepository = $this->container->get('country.repository');
$locales = $this->getAvailableLocales($context);
$translationLocales = $this->matchByAvailableLocales($locales);
$countryData = [];
for ($i = 0; $i < sizeof($this->csvData); $i++) {
$translationsFull = [];
foreach ($translationLocales as $translationLocale) {
$translationsFull[$translationLocale['locale']] = [
'name' => $this->csvData[$i][$translationLocale['name']],
'customFields' => [
'acris_edit' => true,
'acris_countries_regex' => $this->csvData[$i][6],
'acris_countries_regex_description' => $this->csvData[$i][$translationLocale['acris_countries_regex_description']],
],
];
}
$countryData[] = [
'iso' => $this->csvData[$i][2],
'position' => 10,
'active' => true,
'shippingAvailable' => true,
'iso3' => $this->csvData[$i][11],
'translations' => $translationsFull
];
}
foreach ($countryData as $country) {
$this->createEntityIfNotExists($countryRepository, $context, 'iso', $country);
}
}
/**
* @param EntityRepositoryInterface $entityRepository
* @param Context $context
* @param string $identifierField
* @param array $countryDataFull
*/
private function createEntityIfNotExists(EntityRepositoryInterface $entityRepository, Context $context, string $identifierField, array $countryDataFull): void
{
$shopwareCountries = $entityRepository->search((new Criteria())->addFilter(new EqualsFilter($identifierField, $countryDataFull[$identifierField]))->addAssociation('translations')->addAssociation('translations.language')->addAssociation('translations.language.locale'), $context);
if ($shopwareCountries->getTotal() === 0) {
$entityRepository->upsert([$countryDataFull], $context);
} else {
/** @var CountryEntity $country */
$country = $shopwareCountries->first();
if(empty($country)) {
return;
}
// merge translations by remove existing values
if(!empty($country->getTranslations())) {
foreach ($country->getTranslations()->getElements() as $countryTranslationEntity) {
if($countryTranslationEntity->getLanguage() && $countryTranslationEntity->getLanguage()->getLocale() && $countryTranslationEntity->getLanguage()->getLocale()->getCode()) {
$code = $countryTranslationEntity->getLanguage()->getLocale()->getCode();
if(array_key_exists($code, $countryDataFull['translations'])) {
// when custom fields not empty -> remove custom fields
if($countryTranslationEntity->getCustomFields() !== null && !empty($countryTranslationEntity->getCustomFields())) {
unset($countryDataFull['translations'][$code]['customFields']);
}
// when name not empty -> remove name
if($countryTranslationEntity->getName() !== null && $countryTranslationEntity->getName() !== "") {
unset($countryDataFull['translations'][$code]['name']);
}
if(empty($countryDataFull['translations'][$code])) {
unset($countryDataFull['translations'][$code]);
}
}
}
}
}
$data = [
'id' => $shopwareCountries->first()->getId(),
'translations' => $countryDataFull['translations']
];
$entityRepository->upsert([$data], $context);
}
}
public function uninstall(UninstallContext $context): void
{
if ($context->keepUserData()) {
return;
}
$this->cleanupDatabase($context->getContext());
}
private function cleanupDatabase(Context $context): void
{
/** @var EntityRepositoryInterface $countryRepository */
$countryRepository = $this->container->get('country.repository');
$connection = $this->container->get(Connection::class);
$acrisCountries = $countryRepository->search((new Criteria())->addFilter(new ContainsFilter("customFields", "\"acris_edit\":true")), $context);
foreach ($acrisCountries as $country) {
$id = $country->getId();
$data = [
'id' => $id,
'active' => false,
];
try {
$connection->executeUpdate('DELETE FROM country WHERE lower(HEX(id)) LIKE "' . $id . '"');
} catch (DBALException $e) {
$countryRepository->upsert([$data], $context);
}
}
}
private function matchByAvailableLocales(array $locales): array
{
$matchedLocales = [];
foreach ($locales as $locale) {
foreach (self::COUNTRY_LOCALES_CSV_DATA_MATCH as $csvMatch) {
foreach ($csvMatch['locales'] as $availableLocale) {
if($availableLocale === $locale) {
$matchedLocales[] = [
'locale' => $locale,
'name' => $csvMatch['name'],
'acris_countries_regex_description' => $csvMatch['acris_countries_regex_description']
];
break;
}
}
}
}
return $matchedLocales;
}
}