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`
|
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.
|
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.
|
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
|
## Update project
|
||||||
@@ -16,6 +16,13 @@
|
|||||||
2. Run `git pull`
|
2. Run `git pull`
|
||||||
3. Start and build image in one go with command: `docker compose up -d --build --force-recreate`
|
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
|
## Screenshots
|
||||||
|
|
||||||
### Main screen of the web view
|
### Main screen of the web view
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
php-app:
|
php-app:
|
||||||
|
restart: unless-stopped
|
||||||
build: .
|
build: .
|
||||||
volumes:
|
volumes:
|
||||||
- .:/usr/src/app
|
- .:/usr/src/app
|
||||||
|
|||||||
@@ -8,7 +8,11 @@ final class ProductController extends BaseController
|
|||||||
{
|
{
|
||||||
public function __invoke(int $productId): void
|
public function __invoke(int $productId): void
|
||||||
{
|
{
|
||||||
$product = Product::with('price')->find($productId);
|
$product = Product::with([
|
||||||
$this->twig->display('product.html.twig', ['product' => $product ?? []]);
|
'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'>
|
<table class='table table-hover'>
|
||||||
<tr>
|
<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 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><img src='{{ product.image }}&width=150' class='border rounded p-1' alt='{{ product.name }}'/></td>
|
||||||
<td><a href='/product/{{ product.id }}'>{{ product.name }}</a></td>
|
<td><a href='/product/{{ product.id }}' class="text-decoration-none">{{ product.name }}</a></td>
|
||||||
<td>{{ product.subTitle }}</td>
|
<td>{{ product.subTitle }}</td>
|
||||||
<td>
|
<td>
|
||||||
<ul class='nav'>
|
<ul class='nav'>
|
||||||
@@ -16,6 +16,13 @@
|
|||||||
</td>
|
</td>
|
||||||
<td><a href='https://pl.ryobitools.eu/{{ product.url }}'>link</a></td>
|
<td><a href='https://pl.ryobitools.eu/{{ product.url }}'>link</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="4">
|
||||||
|
<div style="width: 800px;">
|
||||||
|
<canvas id="price"></canvas>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="4">
|
<td colspan="4">
|
||||||
<table class='table table-hover table-sm mb-0'>
|
<table class='table table-hover table-sm mb-0'>
|
||||||
@@ -38,5 +45,46 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</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 %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
{% for product in products %}
|
{% for product in products %}
|
||||||
<tr>
|
<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 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" 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 }}'>{{ product.name }}</a></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">{{ product.subTitle }}</td>
|
||||||
<td class="align-middle">
|
<td class="align-middle">
|
||||||
<ul class='nav'>
|
<ul class='nav'>
|
||||||
|
|||||||
Reference in New Issue
Block a user