Autostart docker app unless stopped on purpose. Update README.md and describe cron scheduling. Add chart to product view and sort product prices.

This commit is contained in:
Krzysztof Płaczek
2024-10-15 20:20:57 +02:00
parent d043e8efb1
commit 3cc5d73758
5 changed files with 67 additions and 7 deletions

View File

@@ -7,7 +7,7 @@
3. Build and start docker container `docker compose up -d`
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:9000` address in web browser.
6. Access web interface using `localhost:9001` address in web browser.
## Update project
@@ -16,6 +16,13 @@
2. Run `git pull`
3. Start and build image in one go with command: `docker compose up -d --build --force-recreate`
## Running Cron
For now only way of running `app:scrape` command on schedule is to use host crontab.
1. Run `crontab -e` command to edit host crontab job file
2. Add a new line with e.g. line like this `0 1 * * * cd /var/project/directory/ && docker compose exec php-app php console.php app:scrape`
3. Save and exit file editor. Cron will execute `app:scrape` once per day.
## Screenshots
### Main screen of the web view

View File

@@ -1,5 +1,6 @@
services:
php-app:
restart: unless-stopped
build: .
volumes:
- .:/usr/src/app

View File

@@ -8,7 +8,11 @@ final class ProductController extends BaseController
{
public function __invoke(int $productId): void
{
$product = Product::with('price')->find($productId);
$this->twig->display('product.html.twig', ['product' => $product ?? []]);
$product = Product::with([
'price' => fn($query) => $query->orderBy('created_at', 'desc')
])->find($productId);
$priceList = $product->price()->pluck('price')->implode(',');
$priceDates = $product->price()->pluck('created_at')->map(fn($date) => $date->format('Y-m-d'))->implode("','");
$this->twig->display('product.html.twig', ['product' => $product ?? [], 'price_list' => $priceList, 'price_dates' => $priceDates]);
}
}

View File

@@ -4,8 +4,8 @@
<table class='table table-hover'>
<tr>
<td class="align-middle font-weight-bold h3"><a class="text-warning text-decoration-none" href="/star/{{ product.id }}">{% if product.starred %}{% else %}{% endif %}</a></td>
<td><img src='{{ product.image }}&width=150' class='img-fluid' alt='{{ product.name }}'/></td>
<td><a href='/product/{{ product.id }}'>{{ product.name }}</a></td>
<td><img src='{{ product.image }}&width=150' class='border rounded p-1' alt='{{ product.name }}'/></td>
<td><a href='/product/{{ product.id }}' class="text-decoration-none">{{ product.name }}</a></td>
<td>{{ product.subTitle }}</td>
<td>
<ul class='nav'>
@@ -16,6 +16,13 @@
</td>
<td><a href='https://pl.ryobitools.eu/{{ product.url }}'>link</a></td>
</tr>
<tr>
<td colspan="4">
<div style="width: 800px;">
<canvas id="price"></canvas>
</div>
</td>
</tr>
<tr>
<td colspan="4">
<table class='table table-hover table-sm mb-0'>
@@ -38,5 +45,46 @@
</td>
</tr>
</table>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
const ctx = document.getElementById('price');
new Chart(ctx, {
type: 'line',
data: {
labels: ['{{ price_dates|raw }}'],
datasets: [{
label: 'Price (PLN)',
data: [{{ price_list }}],
borderWidth: 1
}]
},
options: {
animation: false,
plugins: {
title: {
display: true,
text: 'Price in time'
},
},
scales: {
x: {
title: {
display: true,
text: 'Date'
}
},
y: {
beginAtZero: true,
title: {
display: true,
text: 'Price'
}
}
}
}
});
</script>
{% endblock %}

View File

@@ -5,8 +5,8 @@
{% for product in products %}
<tr>
<td class="align-middle font-weight-bold h3"><a class="text-warning text-decoration-none" href="/star/{{ product.id }}">{% if product.starred %}{% else %}{% endif %}</a></td>
<td><img src='{{ product.image }}&width=70' class='img-fluid' alt='{{ product.name }}'/></td>
<td class="align-middle"><a href='/product/{{ product.id }}'>{{ product.name }}</a></td>
<td class="align-middle" style="width: 120px;"><img src='{{ product.image }}&width=70' class='border rounded p-1' alt='{{ product.name }}'/></td>
<td class="align-middle"><a href='/product/{{ product.id }}' class="text-decoration-none">{{ product.name }}</a></td>
<td class="align-middle">{{ product.subTitle }}</td>
<td class="align-middle">
<ul class='nav'>