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:
@@ -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
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
services:
|
||||
php-app:
|
||||
restart: unless-stopped
|
||||
build: .
|
||||
volumes:
|
||||
- .:/usr/src/app
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
|
||||
@@ -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'>
|
||||
|
||||
Reference in New Issue
Block a user