diff --git a/app/Importers/BinBinDataImporter.php b/app/Importers/BinBinDataImporter.php new file mode 100644 index 00000000..c21f2571 --- /dev/null +++ b/app/Importers/BinBinDataImporter.php @@ -0,0 +1,73 @@ +client->get("https://www.binbin.tech/lokasyonlar"); + $html = $response->getBody()->getContents(); + } catch (GuzzleException) { + $this->createImportInfoDetails("400", self::getProviderName()); + + $this->stopExecution = true; + + return $this; + } + + $crawler = new Crawler($html); + $this->sections = $crawler->filter(".location-wrapper .cities-information .div-block-35"); + + if (count($this->sections) === 0) { + $this->createImportInfoDetails("204", self::getProviderName()); + + $this->stopExecution = true; + } + + return $this; + } + + public function transform(): void + { + if ($this->stopExecution) { + return; + } + + $existingCityProviders = []; + + foreach ($this->sections as $section) { + $data = explode("|", $section->nodeValue); + + if (trim($data[1]) === "Türkiye") { + $countryName = "Turkey"; + } else { + $countryName = $this->translate(trim($data[1]), self::LANGUAGE); + } + + if (trim($data[0]) === "Uşak") { + $cityName = "Usak"; + } elseif (trim($data[0]) === "Murter") { + continue; + } else { + $cityName = $this->translate(trim($data[0]), "en"); + } + + $provider = $this->load($cityName, $countryName); + + if ($provider !== "") $existingCityProviders[] = $provider; + } + + $this->deleteMissingProviders(self::getProviderName(), $existingCityProviders); + } +} diff --git a/app/Importers/DataImporter.php b/app/Importers/DataImporter.php index e3f286ae..d0267acf 100644 --- a/app/Importers/DataImporter.php +++ b/app/Importers/DataImporter.php @@ -12,16 +12,20 @@ use App\Models\ImportInfoDetail; use App\Services\MapboxGeocodingService; use GuzzleHttp\Client; +use Stichoza\GoogleTranslate\GoogleTranslate; abstract class DataImporter { protected bool $stopExecution = false; protected int $importInfoId; + protected GoogleTranslate $translate; public function __construct( protected Client $client, protected MapboxGeocodingService $mapboxService, - ) {} + ) { + $this->translate = new GoogleTranslate(); + } public function setImportInfo(int $importInfoId): static { @@ -48,6 +52,11 @@ public static function getProviderName(): string return $classNameParts[0]; } + public function translate(string $word, string $language): string + { + return $this->translate->setTarget($language)->translate($word); + } + protected function countryNotFound(string $cityName, string $countryName): void { CityWithoutAssignedCountry::query()->updateOrCreate( diff --git a/app/Importers/LinkDataImporter.php b/app/Importers/LinkDataImporter.php new file mode 100644 index 00000000..db205eef --- /dev/null +++ b/app/Importers/LinkDataImporter.php @@ -0,0 +1,86 @@ +client->get("https://superpedestrian.com/locations"); + $html = $response->getBody()->getContents(); + } catch (GuzzleException) { + $this->createImportInfoDetails("400", self::getProviderName()); + + $this->stopExecution = true; + + return $this; + } + + $crawler = new Crawler($html); + $this->sections = $crawler->filter(".Main-content .sqs-row.row > .col p > strong"); + + if (count($this->sections) === 0) { + $this->createImportInfoDetails("204", self::getProviderName()); + + $this->stopExecution = true; + } + + return $this; + } + + public function transform(): void + { + if ($this->stopExecution) { + return; + } + + $existingCityProviders = []; + + foreach ($this->sections as $section) { + foreach ($section->childNodes as $node) { + $countryName = trim($node->nodeValue); + + foreach ($node->parentNode->parentNode->parentNode->childNodes as $i => $cityName) { + if ($i === 0 || !trim($cityName->nodeValue)) { + continue; + } + + $name = $cityName->nodeValue; + + $cities = []; + + if (str_contains($name, "(") && str_contains($name, ")")) { + $names = explode("(", $name)[1]; + $names = explode(")", $names)[0]; + $names = explode(", ", $names); + + foreach ($names as $name) { + $cities[] = str_replace("*", "", $name); + } + } else { + $cities[] = $name; + } + + foreach ($cities as $name) { + $provider = $this->load($name, $countryName); + + if ($provider !== "") { + $existingCityProviders[] = $provider; + } + } + } + } + } + + $this->deleteMissingProviders(self::getProviderName(), $existingCityProviders); + } +} diff --git a/app/Jobs/BinBinDataImporterJob.php b/app/Jobs/BinBinDataImporterJob.php new file mode 100644 index 00000000..eab48525 --- /dev/null +++ b/app/Jobs/BinBinDataImporterJob.php @@ -0,0 +1,15 @@ +setImportInfo($this->importInfoId)->extract()->transform(); + } +} diff --git a/app/Jobs/LinkDataImporterJob.php b/app/Jobs/LinkDataImporterJob.php new file mode 100644 index 00000000..e7a84ea3 --- /dev/null +++ b/app/Jobs/LinkDataImporterJob.php @@ -0,0 +1,15 @@ +setImportInfo($this->importInfoId)->extract()->transform(); + } +} diff --git a/app/Services/DataImporterService.php b/app/Services/DataImporterService.php index dd9e900b..a9b161b2 100644 --- a/app/Services/DataImporterService.php +++ b/app/Services/DataImporterService.php @@ -6,12 +6,14 @@ use App\Jobs\BeamDataImporterJob; use App\Jobs\BerylDataImporterJob; +use App\Jobs\BinBinDataImporterJob; use App\Jobs\BirdDataImporterJob; use App\Jobs\BitMobilityDataImporterJob; use App\Jobs\BoltDataImporterJob; use App\Jobs\DottDataImporterJob; use App\Jobs\HulajDataImporterJob; use App\Jobs\LimeDataImporterJob; +use App\Jobs\LinkDataImporterJob; use App\Jobs\NeuronDataImporterJob; use App\Jobs\QuickDataImporterJob; use App\Jobs\RydeDataImporterJob; @@ -40,12 +42,14 @@ public function run(string $whoRunsIt = "admin"): void Bus::batch([ new BeamDataImporterJob($this->importInfoId), new BerylDataImporterJob($this->importInfoId), + new BinBinDataImporterJob($this->importInfoId), new BirdDataImporterJob($this->importInfoId), new BitMobilityDataImporterJob($this->importInfoId), new BoltDataImporterJob($this->importInfoId), new DottDataImporterJob($this->importInfoId), new HulajDataImporterJob($this->importInfoId), new LimeDataImporterJob($this->importInfoId), + new LinkDataImporterJob($this->importInfoId), new NeuronDataImporterJob($this->importInfoId), new QuickDataImporterJob($this->importInfoId), new RydeDataImporterJob($this->importInfoId), diff --git a/database/seeders/ProviderSeeder.php b/database/seeders/ProviderSeeder.php index 3f30860c..28b1a2a8 100644 --- a/database/seeders/ProviderSeeder.php +++ b/database/seeders/ProviderSeeder.php @@ -6,12 +6,14 @@ use App\Importers\BeamDataImporter; use App\Importers\BerylDataImporter; +use App\Importers\BinBinDataImporter; use App\Importers\BirdDataImporter; use App\Importers\BitMobilityDataImporter; use App\Importers\BoltDataImporter; use App\Importers\DottDataImporter; use App\Importers\HulajDataImporter; use App\Importers\LimeDataImporter; +use App\Importers\LinkDataImporter; use App\Importers\NeuronDataImporter; use App\Importers\QuickDataImporter; use App\Importers\RydeDataImporter; @@ -31,12 +33,14 @@ public function run(): void $providers = [ ["name" => BeamDataImporter::getProviderName(), "color" => "#7347ff"], ["name" => BerylDataImporter::getProviderName(), "color" => "#00e3c2"], + ["name" => BinBinDataImporter::getProviderName(), "color" => "#3dbcc8"], ["name" => BirdDataImporter::getProviderName(), "color" => "#26ccf0"], ["name" => BitMobilityDataImporter::getProviderName(), "color" => "#8da6e3"], ["name" => BoltDataImporter::getProviderName(), "color" => "#24f0a0"], ["name" => DottDataImporter::getProviderName(), "color" => "#f5c604"], ["name" => HulajDataImporter::getProviderName(), "color" => "#d6213f"], ["name" => LimeDataImporter::getProviderName(), "color" => "#00de00"], + ["name" => LinkDataImporter::getProviderName(), "color" => "#def700"], ["name" => NeuronDataImporter::getProviderName(), "color" => "#445261"], ["name" => QuickDataImporter::getProviderName(), "color" => "#009ac7"], ["name" => SpinDataImporter::getProviderName(), "color" => "#ff5436"], diff --git a/readme.md b/readme.md index efee97ad..e1dc62f0 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,26 @@ ## 🛴 escooters +### Available providers + +1. Beam +1. Beryl +1. BinBin +1. Bird +1. BitMobility +1. Bolt +1. Dott +1. Hulaj +1. Lime +1. Link +1. Neuron +1. Quick +1. Ryde +1. Spin +1. Tier +1. Urent +1. Veo +1. Voi +1. Zwings + ### Local development ``` cp .env.example .env diff --git a/tests/Unit/ImporterTest.php b/tests/Unit/ImporterTest.php index cd259230..be236c25 100644 --- a/tests/Unit/ImporterTest.php +++ b/tests/Unit/ImporterTest.php @@ -17,6 +17,7 @@ use GuzzleHttp\Psr7\Request; use GuzzleHttp\Psr7\Response; use PHPUnit\Framework\MockObject\Exception; +use Stichoza\GoogleTranslate\GoogleTranslate; use Tests\TestCase; class ImporterTest extends TestCase @@ -41,6 +42,8 @@ protected function setUp(): void $handlerStack = HandlerStack::create($mockHandler); $mockHttpClient = new Client(["handler" => $handlerStack]); + $mockGoogleTranslate = $this->createMock(GoogleTranslate::class); + $mockMapboxService = $this->createMock(MapboxGeocodingService::class); $mockMapboxService->method("getPlaceFromApi")->willReturn(["Perth", "Australia"]); $mockMapboxService->method("getCoordinatesFromApi")