diff --git a/src/Command/Migrate.php b/src/Command/Migrate.php index 1b6c702..96880d5 100644 --- a/src/Command/Migrate.php +++ b/src/Command/Migrate.php @@ -11,6 +11,7 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use function Symfony\Component\Clock\now; #[AsCommand(name: 'app:migrate', description: 'Create database and rum migrations')] class Migrate extends Command @@ -39,6 +40,8 @@ class Migrate extends Command $this->createPricesTable(); $this->createStocksTable(); $this->addColumns(); + $this->createCountriesTable(); + $this->index(); return Command::SUCCESS; } @@ -77,6 +80,47 @@ class Migrate extends Command } } + public function createCountriesTable(): void + { + if (!Capsule::schema()->hasTable('countries')) { + Capsule::schema()->create('countries', function (Blueprint $table) { + $table->increments('id'); + $table->text('countryName'); + $table->text('productsUrl'); + $table->text('cultureCode'); + $table->text('currency'); + $table->text('locale'); + $table->timestamps(); + }); + } + $id = Capsule::table('countries')->insertGetId( + [ + 'countryName' => 'Poland', + 'productsUrl' => 'https://pl.ryobitools.eu/api/product-listing/get-products', + 'cultureCode' => 'pl-PL', + 'currency' => 'PLN', + 'locale' => 'pl', + 'created_at' => now(), + 'updated_at' => now(), + ]); + Capsule::table('countries')->insert([ + 'countryName' => 'UK', + 'productsUrl' => 'https://uk.ryobitools.eu/api/product-listing/get-products', + 'cultureCode' => 'en-GB', + 'currency' => 'GBP', + 'locale' => 'en', + 'created_at' => now(), + 'updated_at' => now(), + ] + ); + + if (!Capsule::schema()->hasColumn('products', 'country_id')) { + Capsule::schema()->table('products', function (Blueprint $table) use ($id) { + $table->foreignId('country_id')->default($id)->references('id')->on('countries'); + }); + } + } + public function createStocksTable(): void { if (!Capsule::schema()->hasTable('stocks')) { @@ -127,4 +171,12 @@ class Migrate extends Command }); } } + + public function index(): void + { + Capsule::schema()->table('products', function (Blueprint $table) { + $table->integer('skuID')->unique(false)->change(); + $table->unique(['skuID', 'country_id']); + }); + } } diff --git a/src/Command/ScrapeWebsite.php b/src/Command/ScrapeWebsite.php index 1c094b6..9993707 100644 --- a/src/Command/ScrapeWebsite.php +++ b/src/Command/ScrapeWebsite.php @@ -7,7 +7,7 @@ namespace Krzysiej\RyobiCrawler\Command; use GuzzleHttp\Client; use GuzzleHttp\Exception\GuzzleException; use Illuminate\Database\Capsule\Manager as Capsule; -use Illuminate\Support\Facades\Date; +use Krzysiej\RyobiCrawler\Models\Country; use Krzysiej\RyobiCrawler\Models\Price; use Krzysiej\RyobiCrawler\Models\Product; use Krzysiej\RyobiCrawler\Models\Stock; @@ -36,16 +36,21 @@ class ScrapeWebsite extends Command { $output->writeln('Scrape products'); $progress = new ProgressBar($output); - $progress->start(); - $products = $this->getProducts(); - $progress->setMaxSteps(count($products)); - foreach ($products as $product) { - $this->saveProduct($product); - $progress->advance(); + $countries = Country::all(); + foreach($countries as $country) { + $output->writeln('Country name: ' . $country->countryName."\n"); + $progress->start(); + $products = $this->getProducts($country); + $progress->setMaxSteps(count($products)); + foreach ($products as $product) { + $this->saveProduct($product, $country); + $progress->advance(); + } + $progress->finish(); + $output->writeln(''); + $output->writeln('Scrape products - DONE'); + $output->writeln(''); } - $progress->finish(); - $output->writeln('Scrape products - DONE'); - $output->writeln(''); $output->writeln('Update prices'); $products = Product::all(); @@ -69,18 +74,19 @@ class ScrapeWebsite extends Command return Command::SUCCESS; } - private function getProducts(): array + private function getProducts(Country $country): array { $products = []; $page = 0; + do { try { - $res = $this->client->request('POST', 'https://pl.ryobitools.eu/api/product-listing/get-products', [ + $res = $this->client->request('POST', $country->productsUrl, [ 'form_params' => [ "includePreviousPages" => false, "pageIndex" => $page, "pageSize" => 100, - "cultureCode" => "pl-PL", + "cultureCode" => $country->cultureCode, ] ]); $responseObject = json_decode($res->getBody()->getContents()); @@ -95,10 +101,14 @@ class ScrapeWebsite extends Command return $products; } - private function saveProduct(\stdClass $product): void + private function saveProduct(\stdClass $product, Country $country): void { +// if ($product->skuID == 0) { +// dump([$product->skuID, $product->name]); +// } +// return; /** @var Product $productModel */ - $productModel = Product::firstOrNew(['skuID' => $product->skuID]); + $productModel = Product::firstOrNew(['skuID' => $product->skuID, 'country_id' => $country->id]); $productModel->skuID = $product->skuID; $productModel->name = $product->name; @@ -111,6 +121,7 @@ class ScrapeWebsite extends Command $productModel->url = $product->url; $productModel->lastSeen = date("Y-m-d"); $productModel->touch('updated_at'); + $productModel->country()->associate($country); $productModel->save(); $priceExists = $productModel->price()->whereRaw("strftime('%Y-%m-%d', created_at) = ?", [date('Y-m-d')])->exists(); diff --git a/src/Models/Country.php b/src/Models/Country.php new file mode 100644 index 0000000..51e0631 --- /dev/null +++ b/src/Models/Country.php @@ -0,0 +1,24 @@ +hasMany(Product::class); + } +} \ No newline at end of file diff --git a/src/Models/Product.php b/src/Models/Product.php index a44f846..139ddf9 100644 --- a/src/Models/Product.php +++ b/src/Models/Product.php @@ -5,6 +5,7 @@ namespace Krzysiej\RyobiCrawler\Models; use Carbon\Traits\Date; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasOne; @@ -32,6 +33,11 @@ class Product extends Model public $timestamps = true; public $fillable = ['skuID']; + public function country(): BelongsTo + { + return $this->belongsTo(Country::class); + } + public function price(): HasMany { return $this->hasMany(Price::class); diff --git a/templates/product.html.twig b/templates/product.html.twig index b2c1e75..a6ce4dc 100644 --- a/templates/product.html.twig +++ b/templates/product.html.twig @@ -44,9 +44,9 @@ {% for price in product.price %} - {{ price.price | format_currency('PLN', {}, 'pl') }} - {{ price.lowestProductPrice30Days | format_currency('PLN', {}, 'pl') }} - {{ price.productStandardPrice | format_currency('PLN', {}, 'pl') }} + {{ price.price | format_currency(product.country.currency, {}, product.country.locale) }} + {{ price.lowestProductPrice30Days | format_currency(product.country.currency, {}, product.country.locale) }} + {{ price.productStandardPrice | format_currency(product.country.currency, {}, product.country.locale) }} {{ price.created_at }} {{ (product.stock | findByCreatedAtDate(price.created_at | slice(0,10))).stock ?? '' }} @@ -67,7 +67,7 @@ labels: ['{{ price_dates|raw }}'], datasets: [ { - label: 'Price (PLN)', + label: 'Price ({{ product.country.currency }})', data: {{ price_list|raw }}, yAxisID: 'yPrice', tension: 0.1, @@ -99,7 +99,7 @@ beginAtZero: true, title: { display: true, - text: 'Price (PLN)' + text: 'Price ({{ product.country.currency }})' }, grid: { drawOnChartArea: false diff --git a/templates/productList.html.twig b/templates/productList.html.twig index 0fe850e..9aad00d 100644 --- a/templates/productList.html.twig +++ b/templates/productList.html.twig @@ -48,16 +48,16 @@ link {% if product.isDiscontinued() or product.priceCurrent == product.productStandardPrice %} - {{ product.priceLowest | format_currency('PLN', {}, 'pl') }} + {{ product.priceLowest | format_currency(product.country.currency, {}, product.country.locale) }} {% else %} - {% if product.priceLowest != product.priceCurrent %}{{ product.priceLowest | format_currency('PLN', {}, 'pl') }}{%else%}now lowest{% endif %} + {% if product.priceLowest != product.priceCurrent %}{{ product.priceLowest | format_currency(product.country.currency, {}, product.country.locale) }}{%else%}now lowest{% endif %} {% endif %} - {{ product.priceCurrent | format_currency('PLN', {}, 'pl') }} + {{ product.priceCurrent | format_currency(product.country.currency, {}, product.country.locale) }}
{% if product.priceCurrent != product.productStandardPrice %}{{ product.productStandardPrice | format_currency('PLN', {}, 'pl') }} {{ product.productStandardPrice | format_currency(product.country.currency, {}, product.country.locale) }} {{ ((1 - product.priceCurrent / product.productStandardPrice)*100)|number_format(0) }}% {% endif %}