Compare commits
7 Commits
1.2.0
...
76d8b7d9cf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76d8b7d9cf | ||
|
|
f30304cbe9 | ||
| dc287aadc6 | |||
| 708a5eeae0 | |||
|
|
7352eea270 | ||
|
|
e97d976705 | ||
| beb717f9b9 |
@@ -4,7 +4,7 @@
|
||||
|
||||
1. Clone repository using `git clone https://git.techtube.pl/krzysiej/ryobi-crawler.git`
|
||||
2. Cd into project directory `cd ryobi-crawler`
|
||||
3. Build and start docker container `docker compose up -d`
|
||||
3. Build and start docker container `docker compose up -d --build --force-recreate`
|
||||
4. Run `docker compose exec php-app php console.php app:migrate` file to create `database.sqlite` and create tables.
|
||||
5. Run `docker compose exec php-app php console.php app:scrape` command to scrape all the products from the ryobi website.
|
||||
6. Access web interface using `localhost:9001` address in web browser.
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
[ -z "$1" ] && echo "Please specify a Composer command (ex. install)" && exit
|
||||
[ -z "$1" ] && bin/cli composer list && exit
|
||||
bin/cli composer "$@"
|
||||
@@ -42,8 +42,8 @@ class CacheWarmCommand extends Command
|
||||
$progress = new ProgressBar($output);
|
||||
$progress->start();
|
||||
$products = Product::with([
|
||||
'price' => fn($query) => $query->orderBy('created_at', 'desc'),
|
||||
'stock' => fn($query) => $query->orderBy('created_at', 'desc'),
|
||||
'price' => fn($query) => $query->orderByDesc('created_at'),
|
||||
'stock' => fn($query) => $query->orderByDesc('created_at'),
|
||||
])->get();
|
||||
$progress->setMaxSteps(count($products));
|
||||
|
||||
|
||||
@@ -21,15 +21,13 @@ class ScrapeWebsite extends Command
|
||||
{
|
||||
private Client $client;
|
||||
|
||||
public function __construct(protected Capsule $database)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$capsule = new Capsule;
|
||||
$capsule->addConnection([
|
||||
'driver' => 'sqlite',
|
||||
'database' => __DIR__ . '/../../database.sqlite',
|
||||
]);
|
||||
$capsule->setAsGlobal();
|
||||
$capsule->bootEloquent();
|
||||
$this->client = new Client();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,7 @@ class BaseController extends AbstractController
|
||||
{
|
||||
protected Environment $twig;
|
||||
|
||||
public function __construct(protected FilesystemAdapter $cache)
|
||||
public function __construct(protected FilesystemAdapter $cache, protected Capsule $database)
|
||||
{
|
||||
$capsule = new Capsule;
|
||||
$capsule->addConnection(['driver' => 'sqlite', 'database' => __DIR__ . '/../../database.sqlite']);
|
||||
$capsule->setAsGlobal();
|
||||
$capsule->bootEloquent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ final class CategoryController extends BaseController
|
||||
return $this->render('productList.html.twig', ['listType' => 'category_'.$category]);
|
||||
}
|
||||
|
||||
$products = Product::with('price')
|
||||
$products = Product::with(['price', 'lowestPrice'])
|
||||
->selectRaw('products.*')
|
||||
->distinct('products.id')
|
||||
->fromRaw('products, json_each(products.categories)')
|
||||
|
||||
@@ -20,7 +20,7 @@ final class DiscontinuedController extends BaseController
|
||||
$products = Product::where('updated_at', '<', now()->format('Y-m-d'))
|
||||
->orderByDesc('starred')
|
||||
->orderByDesc('created_by')
|
||||
->with(['currentPrice'])
|
||||
->with(['currentPrice', 'lowestPrice'])
|
||||
->get();
|
||||
return $this->render('productList.html.twig', ['products' => $products, 'listType' => 'discontinued']);
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ final class IndexController extends BaseController
|
||||
#[Route('/', name: 'app_home')]
|
||||
public function __invoke(): Response
|
||||
{
|
||||
if($this->cache->getItem('list_all')->isHit()) {
|
||||
if ($this->cache->getItem('list_all')->isHit()) {
|
||||
return $this->render('productList.html.twig', ['listType' => 'all']);
|
||||
}
|
||||
$products = Product::with(['currentStock', 'price'])
|
||||
$products = Product::with(['currentStock', 'price', 'lowestPrice'])
|
||||
->orderByDesc('starred')
|
||||
->orderByDesc('created_by')
|
||||
->get();
|
||||
|
||||
@@ -21,7 +21,7 @@ final class NewController extends BaseController
|
||||
$products = Product::where('created_at', '>', now()->modify('-30 days')->format('Y-m-d'))
|
||||
->orderByDesc('starred')
|
||||
->orderByDesc('created_by')
|
||||
->with(['currentPrice'])
|
||||
->with(['currentPrice', 'lowestPrice'])
|
||||
->get();
|
||||
return $this->render('productList.html.twig', ['products' => $products, 'listType' => 'new']);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ final class PromosController extends BaseController
|
||||
$products = Product::whereHas('currentPrice', fn(Builder $query) => $query->whereColumn('price', '<', 'productStandardPrice'))
|
||||
->orderByDesc('starred')
|
||||
->orderByDesc('created_by')
|
||||
->with(['currentPrice'])
|
||||
->with(['currentPrice', 'lowestPrice'])
|
||||
->get();
|
||||
return $this->render('productList.html.twig', ['products' => $products, 'listType' => 'promos']);
|
||||
}
|
||||
|
||||
14
src/DatabaseFactory.php
Normal file
14
src/DatabaseFactory.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Krzysiej\RyobiCrawler;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager as Capsule;
|
||||
class DatabaseFactory
|
||||
{
|
||||
public static function create(Capsule $capsule): void
|
||||
{
|
||||
$capsule->addConnection(['driver' => 'sqlite', 'database' => __DIR__ . '/../database.sqlite']);
|
||||
$capsule->setAsGlobal();
|
||||
$capsule->bootEloquent();
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Krzysiej\RyobiCrawler;
|
||||
|
||||
use Illuminate\Database\Capsule\Manager;
|
||||
use Krzysiej\RyobiCrawler\Twig\AppExtension;
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
@@ -34,14 +35,13 @@ class Kernel extends BaseKernel
|
||||
'secret' => 'S0ME_SECRET'
|
||||
]);
|
||||
$services = $container->services()->defaults()->autowire()->autoconfigure();
|
||||
$services->load('Krzysiej\\RyobiCrawler\\Controller\\', __DIR__ . '/Controller/*');
|
||||
$services->load('Krzysiej\\RyobiCrawler\\Command\\', __DIR__ . '/Command/*')->tag('console.command');
|
||||
$services->set(Manager::class)->configurator([DatabaseFactory::class, 'create']);
|
||||
$services->load('Krzysiej\\RyobiCrawler\\', __DIR__ )
|
||||
->exclude('../src/{Models,Twig,DatabaseFactory.php,Kernel.php}');
|
||||
$services->set('twig.extension.cache', AppExtension::class)->tag('twig.extension');
|
||||
$services->set(CacheExtension::class)->tag('twig.extension');
|
||||
$services->set(FilesystemAdapter::class)->args([
|
||||
'', // namespace
|
||||
0, // default lifetime
|
||||
__DIR__ . '/../var/cache/twig_blocks' // custom path
|
||||
'$directory' => __DIR__ . '/../var/cache/twig_blocks'
|
||||
]);
|
||||
$services->set('twig.runtime.cache', CacheRuntime::class)->args([new Reference(FilesystemAdapter::class)])->tag('twig.runtime');
|
||||
}
|
||||
|
||||
@@ -41,6 +41,11 @@ class Product extends Model
|
||||
return $this->hasOne(Price::class)->latestOfMany('created_at');
|
||||
}
|
||||
|
||||
public function lowestPrice(): HasOne
|
||||
{
|
||||
return $this->hasOne(Price::class)->ofMany('price', 'MIN');
|
||||
}
|
||||
|
||||
public function stock(): HasMany
|
||||
{
|
||||
return $this->hasMany(Stock::class);
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
<th>Name</th>
|
||||
<th>Categories</th>
|
||||
<th></th>
|
||||
<th>Price</th>
|
||||
<th class="text-end">Lowest Price</th>
|
||||
<th class="text-end">Current Price</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -45,7 +46,8 @@
|
||||
</nav>
|
||||
</td>
|
||||
<td class="align-middle"><a href='https://pl.ryobitools.eu/{{ product.url }}'>link</a></td>
|
||||
<td class="align-middle">{{ product.price.last.price | format_currency('PLN', {}, 'pl') }}</td>
|
||||
<td class="align-middle text-end">{% if product.lowestPrice.price != product.price.last.price %}{{ product.lowestPrice.price | format_currency('PLN', {}, 'pl') }}{% endif %}</td>
|
||||
<td class="align-middle text-end">{{ product.price.last.price | format_currency('PLN', {}, 'pl') }}</td>
|
||||
<td class="align-middle">
|
||||
<div class="d-flex flex-row">
|
||||
{% if product.price.last.price != product.price.last.productStandardPrice %}<span
|
||||
|
||||
Reference in New Issue
Block a user